smb2_server: Fix typo in comment.
[Samba.git] / source3 / smbd / smb2_server.c
blobf4862368970a55e7e6cfe20049cef1ba0a787656
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "../lib/util/tevent_ntstatus.h"
28 #include "smbprofile.h"
29 #include "../lib/util/bitmap.h"
30 #include "../librpc/gen_ndr/krb5pac.h"
31 #include "auth.h"
33 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
35 static const struct smbd_smb2_dispatch_table {
36 uint16_t opcode;
37 const char *name;
38 bool need_session;
39 bool need_tcon;
40 bool as_root;
41 uint16_t fileid_ofs;
42 bool allow_invalid_fileid;
43 } smbd_smb2_table[] = {
44 #define _OP(o) .opcode = o, .name = #o
46 _OP(SMB2_OP_NEGPROT),
47 .as_root = true,
48 },{
49 _OP(SMB2_OP_SESSSETUP),
50 .as_root = true,
51 },{
52 _OP(SMB2_OP_LOGOFF),
53 .need_session = true,
54 .as_root = true,
55 },{
56 _OP(SMB2_OP_TCON),
57 .need_session = true,
59 * This call needs to be run as root.
61 * smbd_smb2_request_process_tcon()
62 * calls make_connection_snum(), which will call
63 * change_to_user(), when needed.
65 .as_root = true,
66 },{
67 _OP(SMB2_OP_TDIS),
68 .need_session = true,
69 .need_tcon = true,
70 .as_root = true,
71 },{
72 _OP(SMB2_OP_CREATE),
73 .need_session = true,
74 .need_tcon = true,
75 },{
76 _OP(SMB2_OP_CLOSE),
77 .need_session = true,
78 .need_tcon = true,
79 .fileid_ofs = 0x08,
80 },{
81 _OP(SMB2_OP_FLUSH),
82 .need_session = true,
83 .need_tcon = true,
84 .fileid_ofs = 0x08,
85 },{
86 _OP(SMB2_OP_READ),
87 .need_session = true,
88 .need_tcon = true,
89 .fileid_ofs = 0x10,
90 },{
91 _OP(SMB2_OP_WRITE),
92 .need_session = true,
93 .need_tcon = true,
94 .fileid_ofs = 0x10,
95 },{
96 _OP(SMB2_OP_LOCK),
97 .need_session = true,
98 .need_tcon = true,
99 .fileid_ofs = 0x08,
101 _OP(SMB2_OP_IOCTL),
102 .need_session = true,
103 .need_tcon = true,
104 .fileid_ofs = 0x08,
105 .allow_invalid_fileid = true,
107 _OP(SMB2_OP_CANCEL),
108 .as_root = true,
110 _OP(SMB2_OP_KEEPALIVE),
111 .as_root = true,
113 _OP(SMB2_OP_FIND),
114 .need_session = true,
115 .need_tcon = true,
116 .fileid_ofs = 0x08,
118 _OP(SMB2_OP_NOTIFY),
119 .need_session = true,
120 .need_tcon = true,
121 .fileid_ofs = 0x08,
123 _OP(SMB2_OP_GETINFO),
124 .need_session = true,
125 .need_tcon = true,
126 .fileid_ofs = 0x18,
128 _OP(SMB2_OP_SETINFO),
129 .need_session = true,
130 .need_tcon = true,
131 .fileid_ofs = 0x10,
133 _OP(SMB2_OP_BREAK),
134 .need_session = true,
135 .need_tcon = true,
137 * we do not set
138 * .fileid_ofs here
139 * as LEASE breaks does not
140 * have a file id
145 const char *smb2_opcode_name(uint16_t opcode)
147 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
148 return "Bad SMB2 opcode";
150 return smbd_smb2_table[opcode].name;
153 static const struct smbd_smb2_dispatch_table *smbd_smb2_call(uint16_t opcode)
155 const struct smbd_smb2_dispatch_table *ret = NULL;
157 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
158 return NULL;
161 ret = &smbd_smb2_table[opcode];
163 SMB_ASSERT(ret->opcode == opcode);
165 return ret;
168 static void print_req_vectors(const struct smbd_smb2_request *req)
170 int i;
172 for (i = 0; i < req->in.vector_count; i++) {
173 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
174 (unsigned int)i,
175 (unsigned int)req->in.vector[i].iov_len);
177 for (i = 0; i < req->out.vector_count; i++) {
178 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
179 (unsigned int)i,
180 (unsigned int)req->out.vector[i].iov_len);
184 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
186 if (size < (4 + SMB2_HDR_BODY)) {
187 return false;
190 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
191 return false;
194 return true;
197 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
199 NTSTATUS status;
200 int ret;
202 TALLOC_FREE(sconn->smb1.fde);
204 sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
205 if (sconn->smb2.recv_queue == NULL) {
206 return NT_STATUS_NO_MEMORY;
209 sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
210 if (sconn->smb2.send_queue == NULL) {
211 return NT_STATUS_NO_MEMORY;
214 sconn->smb2.seqnum_low = 0;
215 sconn->smb2.seqnum_range = 1;
216 sconn->smb2.credits_granted = 1;
217 sconn->smb2.max_credits = lp_smb2_max_credits();
218 sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
219 sconn->smb2.max_credits);
220 if (sconn->smb2.credits_bitmap == NULL) {
221 return NT_STATUS_NO_MEMORY;
224 ret = tstream_bsd_existing_socket(sconn, sconn->sock,
225 &sconn->smb2.stream);
226 if (ret == -1) {
227 status = map_nt_error_from_unix(errno);
228 return status;
231 /* Ensure child is set to non-blocking mode */
232 set_blocking(sconn->sock, false);
233 return NT_STATUS_OK;
236 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
237 #define _smb2_setlen(_buf,len) do { \
238 uint8_t *buf = (uint8_t *)_buf; \
239 buf[0] = 0; \
240 buf[1] = ((len)&0xFF0000)>>16; \
241 buf[2] = ((len)&0xFF00)>>8; \
242 buf[3] = (len)&0xFF; \
243 } while (0)
245 static void smb2_setup_nbt_length(struct iovec *vector, int count)
247 size_t len = 0;
248 int i;
250 for (i=1; i < count; i++) {
251 len += vector[i].iov_len;
254 _smb2_setlen(vector[0].iov_base, len);
257 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
259 data_blob_clear_free(&req->first_key);
260 data_blob_clear_free(&req->last_key);
261 return 0;
264 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
266 TALLOC_CTX *mem_pool;
267 struct smbd_smb2_request *req;
269 #if 0
270 /* Enable this to find subtle valgrind errors. */
271 mem_pool = talloc_init("smbd_smb2_request_allocate");
272 #else
273 mem_pool = talloc_pool(mem_ctx, 8192);
274 #endif
275 if (mem_pool == NULL) {
276 return NULL;
279 req = talloc_zero(mem_pool, struct smbd_smb2_request);
280 if (req == NULL) {
281 talloc_free(mem_pool);
282 return NULL;
284 talloc_reparent(mem_pool, mem_ctx, req);
285 TALLOC_FREE(mem_pool);
287 req->last_session_id = UINT64_MAX;
288 req->last_tid = UINT32_MAX;
290 talloc_set_destructor(req, smbd_smb2_request_destructor);
292 return req;
295 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
296 NTTIME now,
297 uint8_t *buf,
298 size_t buflen,
299 TALLOC_CTX *mem_ctx,
300 struct iovec **piov,
301 int *pnum_iov)
303 struct iovec *iov;
304 int num_iov = 1;
305 size_t taken = 0;
306 uint8_t *first_hdr = buf;
307 size_t verified_buflen = 0;
308 uint8_t *tf = NULL;
309 size_t tf_len = 0;
312 * Note: index '0' is reserved for the transport protocol
314 iov = talloc_zero_array(mem_ctx, struct iovec, num_iov);
315 if (iov == NULL) {
316 return NT_STATUS_NO_MEMORY;
319 while (taken < buflen) {
320 size_t len = buflen - taken;
321 uint8_t *hdr = first_hdr + taken;
322 struct iovec *cur;
323 size_t full_size;
324 size_t next_command_ofs;
325 uint16_t body_size;
326 uint8_t *body = NULL;
327 uint32_t dyn_size;
328 uint8_t *dyn = NULL;
329 struct iovec *iov_tmp;
331 if (verified_buflen > taken) {
332 len = verified_buflen - taken;
333 } else {
334 tf = NULL;
335 tf_len = 0;
338 if (len < 4) {
339 DEBUG(10, ("%d bytes left, expected at least %d\n",
340 (int)len, 4));
341 goto inval;
343 if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
344 struct smbXsrv_session *s = NULL;
345 uint64_t uid;
346 struct iovec tf_iov[2];
347 NTSTATUS status;
348 size_t enc_len;
350 if (conn->protocol < PROTOCOL_SMB2_24) {
351 DEBUG(10, ("Got SMB2_TRANSFORM header, "
352 "but dialect[0x%04X] is used\n",
353 conn->smb2.server.dialect));
354 goto inval;
357 if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) {
358 DEBUG(10, ("Got SMB2_TRANSFORM header, "
359 "but not negotiated "
360 "client[0x%08X] server[0x%08X]\n",
361 conn->smb2.client.capabilities,
362 conn->smb2.server.capabilities));
363 goto inval;
366 if (len < SMB2_TF_HDR_SIZE) {
367 DEBUG(1, ("%d bytes left, expected at least %d\n",
368 (int)len, SMB2_TF_HDR_SIZE));
369 goto inval;
371 tf = hdr;
372 tf_len = SMB2_TF_HDR_SIZE;
373 taken += tf_len;
375 hdr = first_hdr + taken;
376 enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
377 uid = BVAL(tf, SMB2_TF_SESSION_ID);
379 if (len < SMB2_TF_HDR_SIZE + enc_len) {
380 DEBUG(1, ("%d bytes left, expected at least %d\n",
381 (int)len,
382 (int)(SMB2_TF_HDR_SIZE + enc_len)));
383 goto inval;
386 status = smb2srv_session_lookup(conn, uid, now, &s);
387 if (s == NULL) {
388 DEBUG(1, ("invalid session[%llu] in "
389 "SMB2_TRANSFORM header\n",
390 (unsigned long long)uid));
391 TALLOC_FREE(iov);
392 return NT_STATUS_USER_SESSION_DELETED;
395 tf_iov[0].iov_base = (void *)tf;
396 tf_iov[0].iov_len = tf_len;
397 tf_iov[1].iov_base = (void *)hdr;
398 tf_iov[1].iov_len = enc_len;
400 status = smb2_signing_decrypt_pdu(s->global->decryption_key,
401 conn->protocol,
402 tf_iov, 2);
403 if (!NT_STATUS_IS_OK(status)) {
404 TALLOC_FREE(iov);
405 return status;
408 verified_buflen = taken + enc_len;
409 len = enc_len;
413 * We need the header plus the body length field
416 if (len < SMB2_HDR_BODY + 2) {
417 DEBUG(10, ("%d bytes left, expected at least %d\n",
418 (int)len, SMB2_HDR_BODY));
419 goto inval;
421 if (IVAL(hdr, 0) != SMB2_MAGIC) {
422 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
423 IVAL(hdr, 0)));
424 goto inval;
426 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
427 DEBUG(10, ("Got HDR len %d, expected %d\n",
428 SVAL(hdr, 4), SMB2_HDR_BODY));
429 goto inval;
432 full_size = len;
433 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
434 body_size = SVAL(hdr, SMB2_HDR_BODY);
436 if (next_command_ofs != 0) {
437 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
438 goto inval;
440 if (next_command_ofs > full_size) {
441 goto inval;
443 full_size = next_command_ofs;
445 if (body_size < 2) {
446 goto inval;
448 body_size &= 0xfffe;
450 if (body_size > (full_size - SMB2_HDR_BODY)) {
452 * let the caller handle the error
454 body_size = full_size - SMB2_HDR_BODY;
456 body = hdr + SMB2_HDR_BODY;
457 dyn = body + body_size;
458 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
460 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
461 num_iov + SMBD_SMB2_NUM_IOV_PER_REQ);
462 if (iov_tmp == NULL) {
463 TALLOC_FREE(iov);
464 return NT_STATUS_NO_MEMORY;
466 iov = iov_tmp;
467 cur = &iov[num_iov];
468 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
470 cur[SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
471 cur[SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
472 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
473 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
474 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
475 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
476 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
477 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
479 taken += full_size;
482 *piov = iov;
483 *pnum_iov = num_iov;
484 return NT_STATUS_OK;
486 inval:
487 TALLOC_FREE(iov);
488 return NT_STATUS_INVALID_PARAMETER;
491 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
492 uint8_t *inbuf, size_t size,
493 struct smbd_smb2_request **_req)
495 struct smbd_smb2_request *req;
496 uint32_t protocol_version;
497 const uint8_t *inhdr = NULL;
498 uint16_t cmd;
499 uint32_t next_command_ofs;
500 NTSTATUS status;
501 NTTIME now;
503 if (size < (4 + SMB2_HDR_BODY + 2)) {
504 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
505 return NT_STATUS_INVALID_PARAMETER;
508 inhdr = inbuf + 4;
510 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
511 if (protocol_version != SMB2_MAGIC) {
512 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
513 protocol_version));
514 return NT_STATUS_INVALID_PARAMETER;
517 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
518 if (cmd != SMB2_OP_NEGPROT) {
519 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
520 cmd));
521 return NT_STATUS_INVALID_PARAMETER;
524 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
525 if (next_command_ofs != 0) {
526 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
527 next_command_ofs));
528 return NT_STATUS_INVALID_PARAMETER;
531 req = smbd_smb2_request_allocate(sconn);
532 if (req == NULL) {
533 return NT_STATUS_NO_MEMORY;
535 req->sconn = sconn;
537 talloc_steal(req, inbuf);
539 req->request_time = timeval_current();
540 now = timeval_to_nttime(&req->request_time);
542 status = smbd_smb2_inbuf_parse_compound(sconn->conn,
543 now,
544 inbuf + NBT_HDR_SIZE,
545 size - NBT_HDR_SIZE,
546 req, &req->in.vector,
547 &req->in.vector_count);
548 if (!NT_STATUS_IS_OK(status)) {
549 TALLOC_FREE(req);
550 return status;
553 req->current_idx = 1;
555 *_req = req;
556 return NT_STATUS_OK;
559 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
560 uint64_t message_id, uint64_t seq_id)
562 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
563 unsigned int offset;
565 if (seq_id < sconn->smb2.seqnum_low) {
566 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
567 "%llu (sequence id %llu) "
568 "(granted = %u, low = %llu, range = %u)\n",
569 (unsigned long long)message_id,
570 (unsigned long long)seq_id,
571 (unsigned int)sconn->smb2.credits_granted,
572 (unsigned long long)sconn->smb2.seqnum_low,
573 (unsigned int)sconn->smb2.seqnum_range));
574 return false;
577 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
578 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
579 "%llu (sequence id %llu) "
580 "(granted = %u, low = %llu, range = %u)\n",
581 (unsigned long long)message_id,
582 (unsigned long long)seq_id,
583 (unsigned int)sconn->smb2.credits_granted,
584 (unsigned long long)sconn->smb2.seqnum_low,
585 (unsigned int)sconn->smb2.seqnum_range));
586 return false;
589 offset = seq_id % sconn->smb2.max_credits;
591 if (bitmap_query(credits_bm, offset)) {
592 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
593 "%llu (sequence id %llu) "
594 "(granted = %u, low = %llu, range = %u) "
595 "(bm offset %u)\n",
596 (unsigned long long)message_id,
597 (unsigned long long)seq_id,
598 (unsigned int)sconn->smb2.credits_granted,
599 (unsigned long long)sconn->smb2.seqnum_low,
600 (unsigned int)sconn->smb2.seqnum_range,
601 offset));
602 return false;
605 /* Mark the message_ids as seen in the bitmap. */
606 bitmap_set(credits_bm, offset);
608 if (seq_id != sconn->smb2.seqnum_low) {
609 return true;
613 * Move the window forward by all the message_id's
614 * already seen.
616 while (bitmap_query(credits_bm, offset)) {
617 DEBUG(10,("smb2_validate_sequence_number: clearing "
618 "id %llu (position %u) from bitmap\n",
619 (unsigned long long)(sconn->smb2.seqnum_low),
620 offset));
621 bitmap_clear(credits_bm, offset);
623 sconn->smb2.seqnum_low += 1;
624 sconn->smb2.seqnum_range -= 1;
625 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
628 return true;
631 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
632 const uint8_t *inhdr)
634 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
635 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
636 uint16_t credit_charge = 1;
637 uint64_t i;
639 if (opcode == SMB2_OP_CANCEL) {
640 /* SMB2_CANCEL requests by definition resend messageids. */
641 return true;
644 if (sconn->smb2.supports_multicredit) {
645 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
646 credit_charge = MAX(credit_charge, 1);
649 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
650 "credits_granted %llu, "
651 "seqnum low/range: %llu/%llu\n",
652 (unsigned long long) message_id,
653 (unsigned long long) credit_charge,
654 (unsigned long long) sconn->smb2.credits_granted,
655 (unsigned long long) sconn->smb2.seqnum_low,
656 (unsigned long long) sconn->smb2.seqnum_range));
658 if (sconn->smb2.credits_granted < credit_charge) {
659 DEBUG(0, ("smb2_validate_message_id: client used more "
660 "credits than granted, mid %llu, charge %llu, "
661 "credits_granted %llu, "
662 "seqnum low/range: %llu/%llu\n",
663 (unsigned long long) message_id,
664 (unsigned long long) credit_charge,
665 (unsigned long long) sconn->smb2.credits_granted,
666 (unsigned long long) sconn->smb2.seqnum_low,
667 (unsigned long long) sconn->smb2.seqnum_range));
668 return false;
672 * now check the message ids
674 * for multi-credit requests we need to check all current mid plus
675 * the implicit mids caused by the credit charge
676 * e.g. current mid = 15, charge 5 => mark 15-19 as used
679 for (i = 0; i <= (credit_charge-1); i++) {
680 uint64_t id = message_id + i;
681 bool ok;
683 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
684 (unsigned long long)message_id,
685 credit_charge,
686 (unsigned long long)id));
688 ok = smb2_validate_sequence_number(sconn, message_id, id);
689 if (!ok) {
690 return false;
694 /* substract used credits */
695 sconn->smb2.credits_granted -= credit_charge;
697 return true;
700 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
702 int count;
703 int idx;
705 count = req->in.vector_count;
707 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
708 /* It's not a SMB2 request */
709 return NT_STATUS_INVALID_PARAMETER;
712 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
713 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
714 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
715 const uint8_t *inhdr = NULL;
717 if (hdr->iov_len != SMB2_HDR_BODY) {
718 return NT_STATUS_INVALID_PARAMETER;
721 if (body->iov_len < 2) {
722 return NT_STATUS_INVALID_PARAMETER;
725 inhdr = (const uint8_t *)hdr->iov_base;
727 /* Check the SMB2 header */
728 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
729 return NT_STATUS_INVALID_PARAMETER;
732 if (!smb2_validate_message_id(req->sconn, inhdr)) {
733 return NT_STATUS_INVALID_PARAMETER;
737 return NT_STATUS_OK;
740 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
741 const struct iovec *in_vector,
742 struct iovec *out_vector)
744 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
745 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
746 uint16_t credit_charge = 1;
747 uint16_t credits_requested;
748 uint32_t out_flags;
749 uint16_t cmd;
750 NTSTATUS out_status;
751 uint16_t credits_granted = 0;
752 uint64_t credits_possible;
753 uint16_t current_max_credits;
756 * first we grant only 1/16th of the max range.
758 * Windows also starts with the 1/16th and then grants
759 * more later. I was only able to trigger higher
760 * values, when using a very high credit charge.
762 * TODO: scale up depending on load, free memory
763 * or other stuff.
764 * Maybe also on the relationship between number
765 * of requests and the used sequence number.
766 * Which means we would grant more credits
767 * for client which use multi credit requests.
769 current_max_credits = sconn->smb2.max_credits / 16;
770 current_max_credits = MAX(current_max_credits, 1);
772 if (sconn->smb2.supports_multicredit) {
773 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
774 credit_charge = MAX(credit_charge, 1);
777 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
778 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
779 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
780 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
782 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
784 if (sconn->smb2.max_credits < credit_charge) {
785 smbd_server_connection_terminate(sconn,
786 "client error: credit charge > max credits\n");
787 return;
790 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
792 * In case we already send an async interim
793 * response, we should not grant
794 * credits on the final response.
796 credits_granted = 0;
797 } else if (credits_requested > 0) {
798 uint16_t additional_max = 0;
799 uint16_t additional_credits = credits_requested - 1;
801 switch (cmd) {
802 case SMB2_OP_NEGPROT:
803 break;
804 case SMB2_OP_SESSSETUP:
806 * Windows 2012 RC1 starts to grant
807 * additional credits
808 * with a successful session setup
810 if (NT_STATUS_IS_OK(out_status)) {
811 additional_max = 32;
813 break;
814 default:
816 * We match windows and only grant additional credits
817 * in chunks of 32.
819 additional_max = 32;
820 break;
823 additional_credits = MIN(additional_credits, additional_max);
825 credits_granted = credit_charge + additional_credits;
826 } else if (sconn->smb2.credits_granted == 0) {
828 * Make sure the client has always at least one credit
830 credits_granted = 1;
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 void smbd_smb2_request_writev_done(struct tevent_req *subreq);
1156 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1158 struct smbXsrv_connection *conn = req->sconn->conn;
1159 int first_idx = 1;
1160 struct iovec *firsttf = NULL;
1161 struct iovec *outhdr_v = NULL;
1162 uint8_t *outhdr = NULL;
1163 struct smbd_smb2_request *nreq = NULL;
1164 NTSTATUS status;
1166 /* Create a new smb2 request we'll use
1167 for the interim return. */
1168 nreq = dup_smb2_req(req);
1169 if (!nreq) {
1170 return NT_STATUS_NO_MEMORY;
1173 /* Lose the last X out vectors. They're the
1174 ones we'll be using for the async reply. */
1175 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1177 smb2_setup_nbt_length(nreq->out.vector,
1178 nreq->out.vector_count);
1180 /* Step back to the previous reply. */
1181 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1182 firsttf = SMBD_SMB2_IDX_TF_IOV(nreq,out,first_idx);
1183 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1184 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1185 /* And end the chain. */
1186 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1188 /* Calculate outgoing credits */
1189 smb2_calculate_credits(req, nreq);
1191 if (DEBUGLEVEL >= 10) {
1192 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1193 (unsigned int)nreq->current_idx );
1194 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1195 (unsigned int)nreq->out.vector_count );
1196 print_req_vectors(nreq);
1200 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1201 * we need to sign/encrypt here with the last/first key we remembered
1203 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
1204 status = smb2_signing_encrypt_pdu(req->first_key,
1205 conn->protocol,
1206 firsttf,
1207 nreq->out.vector_count - first_idx);
1208 if (!NT_STATUS_IS_OK(status)) {
1209 return status;
1211 } else if (req->last_key.length > 0) {
1212 status = smb2_signing_sign_pdu(req->last_key,
1213 conn->protocol,
1214 outhdr_v,
1215 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 return status;
1221 nreq->subreq = tstream_writev_queue_send(nreq,
1222 nreq->sconn->ev_ctx,
1223 nreq->sconn->smb2.stream,
1224 nreq->sconn->smb2.send_queue,
1225 nreq->out.vector,
1226 nreq->out.vector_count);
1228 if (nreq->subreq == NULL) {
1229 return NT_STATUS_NO_MEMORY;
1232 tevent_req_set_callback(nreq->subreq,
1233 smbd_smb2_request_writev_done,
1234 nreq);
1236 return NT_STATUS_OK;
1239 struct smbd_smb2_request_pending_state {
1240 struct smbd_server_connection *sconn;
1241 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1];
1242 struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ];
1245 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
1247 struct smbd_smb2_request_pending_state *state =
1248 tevent_req_callback_data(subreq,
1249 struct smbd_smb2_request_pending_state);
1250 struct smbd_server_connection *sconn = state->sconn;
1251 int ret;
1252 int sys_errno;
1254 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1255 TALLOC_FREE(subreq);
1256 if (ret == -1) {
1257 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1258 smbd_server_connection_terminate(sconn, nt_errstr(status));
1259 return;
1262 TALLOC_FREE(state);
1265 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1266 struct tevent_timer *te,
1267 struct timeval current_time,
1268 void *private_data);
1270 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1271 struct tevent_req *subreq,
1272 uint32_t defer_time)
1274 NTSTATUS status;
1275 int idx = req->current_idx;
1276 struct timeval defer_endtime;
1277 uint8_t *outhdr = NULL;
1278 uint32_t flags;
1280 if (!tevent_req_is_in_progress(subreq)) {
1281 return NT_STATUS_OK;
1284 req->subreq = subreq;
1285 subreq = NULL;
1287 if (req->async_te) {
1288 /* We're already async. */
1289 return NT_STATUS_OK;
1292 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1293 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1294 if (flags & SMB2_HDR_FLAG_ASYNC) {
1295 /* We're already async. */
1296 return NT_STATUS_OK;
1299 if (req->in.vector_count > idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1301 * We're trying to go async in a compound
1302 * request chain. This is not allowed.
1303 * Cancel the outstanding request.
1305 bool ok = tevent_req_cancel(req->subreq);
1306 if (ok) {
1307 return NT_STATUS_OK;
1309 TALLOC_FREE(req->subreq);
1310 return smbd_smb2_request_error(req,
1311 NT_STATUS_INTERNAL_ERROR);
1314 if (DEBUGLEVEL >= 10) {
1315 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1316 (unsigned int)req->current_idx );
1317 print_req_vectors(req);
1320 if (req->out.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ)) {
1322 * This is a compound reply. We
1323 * must do an interim response
1324 * followed by the async response
1325 * to match W2K8R2.
1327 status = smb2_send_async_interim_response(req);
1328 if (!NT_STATUS_IS_OK(status)) {
1329 return status;
1331 data_blob_clear_free(&req->first_key);
1334 * We're splitting off the last SMB2
1335 * request in a compound set, and the
1336 * smb2_send_async_interim_response()
1337 * call above just sent all the replies
1338 * for the previous SMB2 requests in
1339 * this compound set. So we're no longer
1340 * in the "compound_related_in_progress"
1341 * state, and this is no longer a compound
1342 * request.
1344 req->compound_related = false;
1345 req->sconn->smb2.compound_related_in_progress = false;
1347 req->current_idx = 1;
1349 /* Re-arrange the in.vectors. */
1350 memmove(&req->in.vector[req->current_idx],
1351 &req->in.vector[idx],
1352 sizeof(req->in.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1353 req->in.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1355 /* Re-arrange the out.vectors. */
1356 memmove(&req->out.vector[req->current_idx],
1357 &req->out.vector[idx],
1358 sizeof(req->out.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1359 req->out.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1361 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1362 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1363 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1365 data_blob_clear_free(&req->last_key);
1367 defer_endtime = timeval_current_ofs_usec(defer_time);
1368 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1369 req, defer_endtime,
1370 smbd_smb2_request_pending_timer,
1371 req);
1372 if (req->async_te == NULL) {
1373 return NT_STATUS_NO_MEMORY;
1376 return NT_STATUS_OK;
1379 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1380 struct tevent_timer *te,
1381 struct timeval current_time,
1382 void *private_data)
1384 struct smbd_smb2_request *req =
1385 talloc_get_type_abort(private_data,
1386 struct smbd_smb2_request);
1387 struct smbd_smb2_request_pending_state *state = NULL;
1388 uint8_t *outhdr = NULL;
1389 const uint8_t *inhdr = NULL;
1390 uint8_t *tf = NULL;
1391 size_t tf_len = 0;
1392 uint8_t *hdr = NULL;
1393 uint8_t *body = NULL;
1394 uint8_t *dyn = NULL;
1395 uint32_t flags = 0;
1396 uint64_t session_id = 0;
1397 uint64_t message_id = 0;
1398 uint64_t nonce_high = 0;
1399 uint64_t nonce_low = 0;
1400 uint64_t async_id = 0;
1401 struct tevent_req *subreq = NULL;
1403 TALLOC_FREE(req->async_te);
1405 /* Ensure our final reply matches the interim one. */
1406 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1407 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1408 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1409 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1410 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1412 async_id = message_id; /* keep it simple for now... */
1414 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1415 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1417 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1418 "going async\n",
1419 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1420 (unsigned long long)async_id ));
1423 * What we send is identical to a smbd_smb2_request_error
1424 * packet with an error status of STATUS_PENDING. Make use
1425 * of this fact sometime when refactoring. JRA.
1428 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1429 if (state == NULL) {
1430 smbd_server_connection_terminate(req->sconn,
1431 nt_errstr(NT_STATUS_NO_MEMORY));
1432 return;
1434 state->sconn = req->sconn;
1436 tf = state->buf + NBT_HDR_SIZE;
1437 tf_len = SMB2_TF_HDR_SIZE;
1439 hdr = tf + SMB2_TF_HDR_SIZE;
1440 body = hdr + SMB2_HDR_BODY;
1441 dyn = body + 8;
1443 if (req->do_encryption) {
1444 struct smbXsrv_session *x = req->session;
1446 nonce_high = x->nonce_high;
1447 nonce_low = x->nonce_low;
1449 x->nonce_low += 1;
1450 if (x->nonce_low == 0) {
1451 x->nonce_low += 1;
1452 x->nonce_high += 1;
1456 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1457 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1458 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1459 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1461 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1462 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1463 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1464 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1465 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1467 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1468 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1469 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1470 SBVAL(hdr, SMB2_HDR_PID, async_id);
1471 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1472 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1473 memcpy(hdr+SMB2_HDR_SIGNATURE,
1474 outhdr+SMB2_HDR_SIGNATURE, 16);
1476 SSVAL(body, 0x00, 0x08 + 1);
1478 SCVAL(body, 0x02, 0);
1479 SCVAL(body, 0x03, 0);
1480 SIVAL(body, 0x04, 0);
1481 /* Match W2K8R2... */
1482 SCVAL(dyn, 0x00, 0x21);
1484 state->vector[0].iov_base = (void *)state->buf;
1485 state->vector[0].iov_len = NBT_HDR_SIZE;
1487 if (req->do_encryption) {
1488 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1489 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1490 } else {
1491 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1492 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1495 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1496 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1498 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1499 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1501 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1502 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1504 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1506 /* Ensure we correctly go through crediting. Grant
1507 the credits now, and zero credits on the final
1508 response. */
1509 smb2_set_operation_credit(req->sconn,
1510 SMBD_SMB2_IN_HDR_IOV(req),
1511 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1513 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1515 if (DEBUGLVL(10)) {
1516 int i;
1518 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1519 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1520 (unsigned int)i,
1521 (unsigned int)ARRAY_SIZE(state->vector),
1522 (unsigned int)state->vector[i].iov_len);
1526 if (req->do_encryption) {
1527 NTSTATUS status;
1528 struct smbXsrv_session *x = req->session;
1529 struct smbXsrv_connection *conn = x->connection;
1530 DATA_BLOB encryption_key = x->global->encryption_key;
1532 status = smb2_signing_encrypt_pdu(encryption_key,
1533 conn->protocol,
1534 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1535 SMBD_SMB2_NUM_IOV_PER_REQ);
1536 if (!NT_STATUS_IS_OK(status)) {
1537 smbd_server_connection_terminate(req->sconn,
1538 nt_errstr(status));
1539 return;
1541 } else if (req->do_signing) {
1542 NTSTATUS status;
1543 struct smbXsrv_session *x = req->session;
1544 struct smbXsrv_connection *conn = x->connection;
1545 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1547 status = smb2_signing_sign_pdu(signing_key,
1548 conn->protocol,
1549 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1550 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1551 if (!NT_STATUS_IS_OK(status)) {
1552 smbd_server_connection_terminate(req->sconn,
1553 nt_errstr(status));
1554 return;
1558 subreq = tstream_writev_queue_send(state,
1559 state->sconn->ev_ctx,
1560 state->sconn->smb2.stream,
1561 state->sconn->smb2.send_queue,
1562 state->vector,
1563 ARRAY_SIZE(state->vector));
1564 if (subreq == NULL) {
1565 smbd_server_connection_terminate(state->sconn,
1566 nt_errstr(NT_STATUS_NO_MEMORY));
1567 return;
1569 tevent_req_set_callback(subreq,
1570 smbd_smb2_request_pending_writev_done,
1571 state);
1574 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1576 struct smbd_server_connection *sconn = req->sconn;
1577 struct smbd_smb2_request *cur;
1578 const uint8_t *inhdr;
1579 uint32_t flags;
1580 uint64_t search_message_id;
1581 uint64_t search_async_id;
1582 uint64_t found_id;
1584 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1586 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1587 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1588 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1591 * we don't need the request anymore
1592 * cancel requests never have a response
1594 DLIST_REMOVE(req->sconn->smb2.requests, req);
1595 TALLOC_FREE(req);
1597 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1598 const uint8_t *outhdr;
1599 uint64_t message_id;
1600 uint64_t async_id;
1602 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1604 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1605 async_id = BVAL(outhdr, SMB2_HDR_PID);
1607 if (flags & SMB2_HDR_FLAG_ASYNC) {
1608 if (search_async_id == async_id) {
1609 found_id = async_id;
1610 break;
1612 } else {
1613 if (search_message_id == message_id) {
1614 found_id = message_id;
1615 break;
1620 if (cur && cur->subreq) {
1621 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1622 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1623 "cancel opcode[%s] mid %llu\n",
1624 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1625 (unsigned long long)found_id ));
1626 tevent_req_cancel(cur->subreq);
1629 return NT_STATUS_OK;
1632 /*************************************************************
1633 Ensure an incoming tid is a valid one for us to access.
1634 Change to the associated uid credentials and chdir to the
1635 valid tid directory.
1636 *************************************************************/
1638 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1640 const uint8_t *inhdr;
1641 uint32_t in_flags;
1642 uint32_t in_tid;
1643 struct smbXsrv_tcon *tcon;
1644 NTSTATUS status;
1645 NTTIME now = timeval_to_nttime(&req->request_time);
1647 req->tcon = NULL;
1649 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1651 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1652 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1654 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1655 in_tid = req->last_tid;
1658 req->last_tid = 0;
1660 status = smb2srv_tcon_lookup(req->session,
1661 in_tid, now, &tcon);
1662 if (!NT_STATUS_IS_OK(status)) {
1663 return status;
1666 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1667 return NT_STATUS_ACCESS_DENIED;
1670 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1671 if (!set_current_service(tcon->compat, 0, true)) {
1672 return NT_STATUS_ACCESS_DENIED;
1675 req->tcon = tcon;
1676 req->last_tid = in_tid;
1678 return NT_STATUS_OK;
1681 /*************************************************************
1682 Ensure an incoming session_id is a valid one for us to access.
1683 *************************************************************/
1685 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1687 const uint8_t *inhdr;
1688 uint32_t in_flags;
1689 uint16_t in_opcode;
1690 uint64_t in_session_id;
1691 struct smbXsrv_session *session = NULL;
1692 struct auth_session_info *session_info;
1693 NTSTATUS status;
1694 NTTIME now = timeval_to_nttime(&req->request_time);
1696 req->session = NULL;
1697 req->tcon = NULL;
1699 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1701 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1702 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1703 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1705 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1706 in_session_id = req->last_session_id;
1709 req->last_session_id = 0;
1711 /* lookup an existing session */
1712 status = smb2srv_session_lookup(req->sconn->conn,
1713 in_session_id, now,
1714 &session);
1715 if (session) {
1716 req->session = session;
1717 req->last_session_id = in_session_id;
1719 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1720 switch (in_opcode) {
1721 case SMB2_OP_SESSSETUP:
1722 status = NT_STATUS_OK;
1723 break;
1724 default:
1725 break;
1728 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1729 switch (in_opcode) {
1730 case SMB2_OP_TCON:
1731 case SMB2_OP_CREATE:
1732 case SMB2_OP_GETINFO:
1733 case SMB2_OP_SETINFO:
1734 return NT_STATUS_INVALID_HANDLE;
1735 default:
1737 * Notice the check for
1738 * (session_info == NULL)
1739 * below.
1741 status = NT_STATUS_OK;
1742 break;
1745 if (!NT_STATUS_IS_OK(status)) {
1746 return status;
1749 session_info = session->global->auth_session_info;
1750 if (session_info == NULL) {
1751 return NT_STATUS_INVALID_HANDLE;
1754 set_current_user_info(session_info->unix_info->sanitized_username,
1755 session_info->unix_info->unix_name,
1756 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 = IVAL(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;
1913 if (opcode == SMB2_OP_SESSSETUP &&
1914 x->global->channels[0].signing_key.length) {
1915 signing_required = true;
1919 req->do_signing = false;
1920 req->do_encryption = false;
1921 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1922 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1923 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1925 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1926 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1927 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1928 (unsigned long long)x->global->session_wire_id,
1929 (unsigned long long)tf_session_id));
1931 * TODO: windows allows this...
1932 * should we drop the connection?
1934 * For now we just return ACCESS_DENIED
1935 * (Windows clients never trigger this)
1936 * and wait for an update of [MS-SMB2].
1938 return smbd_smb2_request_error(req,
1939 NT_STATUS_ACCESS_DENIED);
1942 req->do_encryption = true;
1945 if (encryption_required && !req->do_encryption) {
1946 return smbd_smb2_request_error(req,
1947 NT_STATUS_ACCESS_DENIED);
1950 call = smbd_smb2_call(opcode);
1951 if (call == NULL) {
1952 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1955 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1956 SMB2_HDR_FLAG_SIGNED |
1957 SMB2_HDR_FLAG_DFS;
1958 if (opcode == SMB2_OP_CANCEL) {
1959 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1961 if ((flags & ~allowed_flags) != 0) {
1962 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1965 if (flags & SMB2_HDR_FLAG_CHAINED) {
1967 * This check is mostly for giving the correct error code
1968 * for compounded requests.
1970 if (!NT_STATUS_IS_OK(session_status)) {
1971 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1973 } else {
1974 req->compat_chain_fsp = NULL;
1977 if (req->do_encryption) {
1978 signing_required = false;
1979 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1980 DATA_BLOB signing_key;
1982 if (x == NULL) {
1983 return smbd_smb2_request_error(
1984 req, NT_STATUS_ACCESS_DENIED);
1987 signing_key = x->global->channels[0].signing_key;
1990 * If we have a signing key, we should
1991 * sign the response
1993 if (signing_key.length > 0) {
1994 req->do_signing = true;
1997 status = smb2_signing_check_pdu(signing_key,
1998 conn->protocol,
1999 SMBD_SMB2_IN_HDR_IOV(req),
2000 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2001 if (!NT_STATUS_IS_OK(status)) {
2002 return smbd_smb2_request_error(req, status);
2006 * Now that we know the request was correctly signed
2007 * we have to sign the response too.
2009 req->do_signing = true;
2011 if (!NT_STATUS_IS_OK(session_status)) {
2012 return smbd_smb2_request_error(req, session_status);
2014 } else if (opcode == SMB2_OP_CANCEL) {
2015 /* Cancel requests are allowed to skip the signing */
2016 } else if (signing_required) {
2018 * If signing is required we try to sign
2019 * a possible error response
2021 req->do_signing = true;
2022 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2025 if (flags & SMB2_HDR_FLAG_CHAINED) {
2026 req->compound_related = true;
2027 req->sconn->smb2.compound_related_in_progress = true;
2030 if (call->need_session) {
2031 if (!NT_STATUS_IS_OK(session_status)) {
2032 return smbd_smb2_request_error(req, session_status);
2036 if (call->need_tcon) {
2037 SMB_ASSERT(call->need_session);
2040 * This call needs to be run as user.
2042 * smbd_smb2_request_check_tcon()
2043 * calls change_to_user() on success.
2045 status = smbd_smb2_request_check_tcon(req);
2046 if (!NT_STATUS_IS_OK(status)) {
2047 return smbd_smb2_request_error(req, status);
2049 if (req->tcon->global->encryption_required) {
2050 encryption_required = true;
2052 if (encryption_required && !req->do_encryption) {
2053 return smbd_smb2_request_error(req,
2054 NT_STATUS_ACCESS_DENIED);
2058 if (call->fileid_ofs != 0) {
2059 size_t needed = call->fileid_ofs + 16;
2060 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2061 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2062 uint64_t file_id_persistent;
2063 uint64_t file_id_volatile;
2064 struct files_struct *fsp;
2066 SMB_ASSERT(call->need_tcon);
2068 if (needed > body_size) {
2069 return smbd_smb2_request_error(req,
2070 NT_STATUS_INVALID_PARAMETER);
2073 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2074 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2076 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2077 if (fsp == NULL) {
2078 if (!call->allow_invalid_fileid) {
2079 return smbd_smb2_request_error(req,
2080 NT_STATUS_FILE_CLOSED);
2083 if (file_id_persistent != UINT64_MAX) {
2084 return smbd_smb2_request_error(req,
2085 NT_STATUS_FILE_CLOSED);
2087 if (file_id_volatile != UINT64_MAX) {
2088 return smbd_smb2_request_error(req,
2089 NT_STATUS_FILE_CLOSED);
2094 if (call->as_root) {
2095 SMB_ASSERT(call->fileid_ofs == 0);
2096 /* This call needs to be run as root */
2097 change_to_root_user();
2098 } else {
2099 SMB_ASSERT(call->need_tcon);
2102 switch (opcode) {
2103 case SMB2_OP_NEGPROT:
2105 START_PROFILE(smb2_negprot);
2106 return_value = smbd_smb2_request_process_negprot(req);
2107 END_PROFILE(smb2_negprot);
2109 break;
2111 case SMB2_OP_SESSSETUP:
2113 START_PROFILE(smb2_sesssetup);
2114 return_value = smbd_smb2_request_process_sesssetup(req);
2115 END_PROFILE(smb2_sesssetup);
2117 break;
2119 case SMB2_OP_LOGOFF:
2121 START_PROFILE(smb2_logoff);
2122 return_value = smbd_smb2_request_process_logoff(req);
2123 END_PROFILE(smb2_logoff);
2125 break;
2127 case SMB2_OP_TCON:
2129 START_PROFILE(smb2_tcon);
2130 return_value = smbd_smb2_request_process_tcon(req);
2131 END_PROFILE(smb2_tcon);
2133 break;
2135 case SMB2_OP_TDIS:
2137 START_PROFILE(smb2_tdis);
2138 return_value = smbd_smb2_request_process_tdis(req);
2139 END_PROFILE(smb2_tdis);
2141 break;
2143 case SMB2_OP_CREATE:
2145 START_PROFILE(smb2_create);
2146 return_value = smbd_smb2_request_process_create(req);
2147 END_PROFILE(smb2_create);
2149 break;
2151 case SMB2_OP_CLOSE:
2153 START_PROFILE(smb2_close);
2154 return_value = smbd_smb2_request_process_close(req);
2155 END_PROFILE(smb2_close);
2157 break;
2159 case SMB2_OP_FLUSH:
2161 START_PROFILE(smb2_flush);
2162 return_value = smbd_smb2_request_process_flush(req);
2163 END_PROFILE(smb2_flush);
2165 break;
2167 case SMB2_OP_READ:
2169 START_PROFILE(smb2_read);
2170 return_value = smbd_smb2_request_process_read(req);
2171 END_PROFILE(smb2_read);
2173 break;
2175 case SMB2_OP_WRITE:
2177 START_PROFILE(smb2_write);
2178 return_value = smbd_smb2_request_process_write(req);
2179 END_PROFILE(smb2_write);
2181 break;
2183 case SMB2_OP_LOCK:
2185 START_PROFILE(smb2_lock);
2186 return_value = smbd_smb2_request_process_lock(req);
2187 END_PROFILE(smb2_lock);
2189 break;
2191 case SMB2_OP_IOCTL:
2193 START_PROFILE(smb2_ioctl);
2194 return_value = smbd_smb2_request_process_ioctl(req);
2195 END_PROFILE(smb2_ioctl);
2197 break;
2199 case SMB2_OP_CANCEL:
2201 START_PROFILE(smb2_cancel);
2202 return_value = smbd_smb2_request_process_cancel(req);
2203 END_PROFILE(smb2_cancel);
2205 break;
2207 case SMB2_OP_KEEPALIVE:
2209 START_PROFILE(smb2_keepalive);
2210 return_value = smbd_smb2_request_process_keepalive(req);
2211 END_PROFILE(smb2_keepalive);
2213 break;
2215 case SMB2_OP_FIND:
2217 START_PROFILE(smb2_find);
2218 return_value = smbd_smb2_request_process_find(req);
2219 END_PROFILE(smb2_find);
2221 break;
2223 case SMB2_OP_NOTIFY:
2225 START_PROFILE(smb2_notify);
2226 return_value = smbd_smb2_request_process_notify(req);
2227 END_PROFILE(smb2_notify);
2229 break;
2231 case SMB2_OP_GETINFO:
2233 START_PROFILE(smb2_getinfo);
2234 return_value = smbd_smb2_request_process_getinfo(req);
2235 END_PROFILE(smb2_getinfo);
2237 break;
2239 case SMB2_OP_SETINFO:
2241 START_PROFILE(smb2_setinfo);
2242 return_value = smbd_smb2_request_process_setinfo(req);
2243 END_PROFILE(smb2_setinfo);
2245 break;
2247 case SMB2_OP_BREAK:
2249 START_PROFILE(smb2_break);
2250 return_value = smbd_smb2_request_process_break(req);
2251 END_PROFILE(smb2_break);
2253 break;
2255 default:
2256 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2257 break;
2259 return return_value;
2262 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2264 struct smbXsrv_connection *conn = req->sconn->conn;
2265 struct tevent_req *subreq;
2266 int first_idx = 1;
2267 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2268 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2269 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2271 req->subreq = NULL;
2272 TALLOC_FREE(req->async_te);
2274 if (req->do_encryption &&
2275 (firsttf->iov_len == 0) &&
2276 (req->first_key.length == 0) &&
2277 (req->session != NULL) &&
2278 (req->session->global->encryption_key.length != 0))
2280 DATA_BLOB encryption_key = req->session->global->encryption_key;
2281 uint8_t *tf;
2282 uint64_t session_id = req->session->global->session_wire_id;
2283 struct smbXsrv_session *x = req->session;
2284 uint64_t nonce_high;
2285 uint64_t nonce_low;
2287 nonce_high = x->nonce_high;
2288 nonce_low = x->nonce_low;
2290 x->nonce_low += 1;
2291 if (x->nonce_low == 0) {
2292 x->nonce_low += 1;
2293 x->nonce_high += 1;
2297 * We need to place the SMB2_TRANSFORM header before the
2298 * first SMB2 header
2302 * we need to remember the encryption key
2303 * and defer the signing/encryption until
2304 * we are sure that we do not change
2305 * the header again.
2307 req->first_key = data_blob_dup_talloc(req, encryption_key);
2308 if (req->first_key.data == NULL) {
2309 return NT_STATUS_NO_MEMORY;
2312 tf = talloc_zero_array(req->out.vector, uint8_t,
2313 SMB2_TF_HDR_SIZE);
2314 if (tf == NULL) {
2315 return NT_STATUS_NO_MEMORY;
2318 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2319 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2320 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2321 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2323 firsttf->iov_base = (void *)tf;
2324 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2327 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2328 (req->last_key.length > 0) &&
2329 (firsttf->iov_len == 0))
2331 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2332 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2333 NTSTATUS status;
2336 * As we are sure the header of the last request in the
2337 * compound chain will not change, we can to sign here
2338 * with the last signing key we remembered.
2340 status = smb2_signing_sign_pdu(req->last_key,
2341 conn->protocol,
2342 lasthdr,
2343 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2344 if (!NT_STATUS_IS_OK(status)) {
2345 return status;
2348 data_blob_clear_free(&req->last_key);
2350 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2352 if (req->current_idx < req->out.vector_count) {
2354 * We must process the remaining compound
2355 * SMB2 requests before any new incoming SMB2
2356 * requests. This is because incoming SMB2
2357 * requests may include a cancel for a
2358 * compound request we haven't processed
2359 * yet.
2361 struct tevent_immediate *im = tevent_create_immediate(req);
2362 if (!im) {
2363 return NT_STATUS_NO_MEMORY;
2366 if (req->do_signing && firsttf->iov_len == 0) {
2367 struct smbXsrv_session *x = req->session;
2368 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2371 * we need to remember the signing key
2372 * and defer the signing until
2373 * we are sure that we do not change
2374 * the header again.
2376 req->last_key = data_blob_dup_talloc(req, signing_key);
2377 if (req->last_key.data == NULL) {
2378 return NT_STATUS_NO_MEMORY;
2382 tevent_schedule_immediate(im,
2383 req->sconn->ev_ctx,
2384 smbd_smb2_request_dispatch_immediate,
2385 req);
2386 return NT_STATUS_OK;
2389 if (req->compound_related) {
2390 req->compound_related = false;
2391 req->sconn->smb2.compound_related_in_progress = false;
2394 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2396 /* Set credit for these operations (zero credits if this
2397 is a final reply for an async operation). */
2398 smb2_calculate_credits(req, req);
2401 * now check if we need to sign the current response
2403 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2404 NTSTATUS status;
2406 status = smb2_signing_encrypt_pdu(req->first_key,
2407 conn->protocol,
2408 firsttf,
2409 req->out.vector_count - first_idx);
2410 if (!NT_STATUS_IS_OK(status)) {
2411 return status;
2413 } else if (req->do_signing) {
2414 NTSTATUS status;
2415 struct smbXsrv_session *x = req->session;
2416 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2418 status = smb2_signing_sign_pdu(signing_key,
2419 conn->protocol,
2420 outhdr,
2421 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2422 if (!NT_STATUS_IS_OK(status)) {
2423 return status;
2426 data_blob_clear_free(&req->first_key);
2428 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2429 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2430 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2431 /* Dynamic part is NULL. Chop it off,
2432 We're going to send it via sendfile. */
2433 req->out.vector_count -= 1;
2436 subreq = tstream_writev_queue_send(req,
2437 req->sconn->ev_ctx,
2438 req->sconn->smb2.stream,
2439 req->sconn->smb2.send_queue,
2440 req->out.vector,
2441 req->out.vector_count);
2442 if (subreq == NULL) {
2443 return NT_STATUS_NO_MEMORY;
2445 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2447 * We're done with this request -
2448 * move it off the "being processed" queue.
2450 DLIST_REMOVE(req->sconn->smb2.requests, req);
2452 return NT_STATUS_OK;
2455 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2457 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2458 struct tevent_immediate *im,
2459 void *private_data)
2461 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2462 struct smbd_smb2_request);
2463 struct smbd_server_connection *sconn = req->sconn;
2464 NTSTATUS status;
2466 TALLOC_FREE(im);
2468 if (DEBUGLEVEL >= 10) {
2469 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2470 req->current_idx, req->in.vector_count));
2471 print_req_vectors(req);
2474 status = smbd_smb2_request_dispatch(req);
2475 if (!NT_STATUS_IS_OK(status)) {
2476 smbd_server_connection_terminate(sconn, nt_errstr(status));
2477 return;
2480 status = smbd_smb2_request_next_incoming(sconn);
2481 if (!NT_STATUS_IS_OK(status)) {
2482 smbd_server_connection_terminate(sconn, nt_errstr(status));
2483 return;
2487 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2489 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2490 struct smbd_smb2_request);
2491 struct smbd_server_connection *sconn = req->sconn;
2492 int ret;
2493 int sys_errno;
2494 NTSTATUS status;
2496 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2497 TALLOC_FREE(subreq);
2498 TALLOC_FREE(req);
2499 if (ret == -1) {
2500 status = map_nt_error_from_unix(sys_errno);
2501 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2502 nt_errstr(status)));
2503 smbd_server_connection_terminate(sconn, nt_errstr(status));
2504 return;
2507 status = smbd_smb2_request_next_incoming(sconn);
2508 if (!NT_STATUS_IS_OK(status)) {
2509 smbd_server_connection_terminate(sconn, nt_errstr(status));
2510 return;
2514 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2515 NTSTATUS status,
2516 DATA_BLOB body, DATA_BLOB *dyn,
2517 const char *location)
2519 uint8_t *outhdr;
2520 struct iovec *outbody_v;
2521 struct iovec *outdyn_v;
2522 uint32_t next_command_ofs;
2524 DEBUG(10,("smbd_smb2_request_done_ex: "
2525 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2526 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2527 dyn ? "yes": "no",
2528 (unsigned int)(dyn ? dyn->length : 0),
2529 location));
2531 if (body.length < 2) {
2532 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2535 if ((body.length % 2) != 0) {
2536 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2539 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2540 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2541 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2543 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2544 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2546 outbody_v->iov_base = (void *)body.data;
2547 outbody_v->iov_len = body.length;
2549 if (dyn) {
2550 outdyn_v->iov_base = (void *)dyn->data;
2551 outdyn_v->iov_len = dyn->length;
2552 } else {
2553 outdyn_v->iov_base = NULL;
2554 outdyn_v->iov_len = 0;
2557 /* see if we need to recalculate the offset to the next response */
2558 if (next_command_ofs > 0) {
2559 next_command_ofs = SMB2_HDR_BODY;
2560 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2561 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2564 if ((next_command_ofs % 8) != 0) {
2565 size_t pad_size = 8 - (next_command_ofs % 8);
2566 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2568 * if the dyn buffer is empty
2569 * we can use it to add padding
2571 uint8_t *pad;
2573 pad = talloc_zero_array(req->out.vector,
2574 uint8_t, pad_size);
2575 if (pad == NULL) {
2576 return smbd_smb2_request_error(req,
2577 NT_STATUS_NO_MEMORY);
2580 outdyn_v->iov_base = (void *)pad;
2581 outdyn_v->iov_len = pad_size;
2582 } else {
2584 * For now we copy the dynamic buffer
2585 * and add the padding to the new buffer
2587 size_t old_size;
2588 uint8_t *old_dyn;
2589 size_t new_size;
2590 uint8_t *new_dyn;
2592 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2593 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2595 new_size = old_size + pad_size;
2596 new_dyn = talloc_zero_array(req->out.vector,
2597 uint8_t, new_size);
2598 if (new_dyn == NULL) {
2599 return smbd_smb2_request_error(req,
2600 NT_STATUS_NO_MEMORY);
2603 memcpy(new_dyn, old_dyn, old_size);
2604 memset(new_dyn + old_size, 0, pad_size);
2606 outdyn_v->iov_base = (void *)new_dyn;
2607 outdyn_v->iov_len = new_size;
2609 next_command_ofs += pad_size;
2612 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2614 return smbd_smb2_request_reply(req);
2617 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2618 NTSTATUS status,
2619 DATA_BLOB *info,
2620 const char *location)
2622 DATA_BLOB body;
2623 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2625 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2626 req->current_idx, nt_errstr(status), info ? " +info" : "",
2627 location));
2629 body.data = outhdr + SMB2_HDR_BODY;
2630 body.length = 8;
2631 SSVAL(body.data, 0, 9);
2633 if (info) {
2634 SIVAL(body.data, 0x04, info->length);
2635 } else {
2636 /* Allocated size of req->out.vector[i].iov_base
2637 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2638 * 1 byte without having to do an alloc.
2640 info = talloc_zero_array(req->out.vector,
2641 DATA_BLOB,
2643 if (!info) {
2644 return NT_STATUS_NO_MEMORY;
2646 info->data = ((uint8_t *)outhdr) +
2647 OUTVEC_ALLOC_SIZE - 1;
2648 info->length = 1;
2649 SCVAL(info->data, 0, 0);
2653 * Note: Even if there is an error, continue to process the request.
2654 * per MS-SMB2.
2657 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2661 struct smbd_smb2_send_oplock_break_state {
2662 struct smbd_server_connection *sconn;
2663 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18];
2664 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2667 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2669 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2670 struct smbXsrv_session *session,
2671 struct smbXsrv_tcon *tcon,
2672 struct smbXsrv_open *op,
2673 uint8_t oplock_level)
2675 struct smbd_smb2_send_oplock_break_state *state;
2676 struct smbXsrv_connection *conn = sconn->conn;
2677 struct tevent_req *subreq;
2678 uint8_t *tf;
2679 size_t tf_len;
2680 uint8_t *hdr;
2681 uint8_t *body;
2682 size_t body_len;
2683 uint8_t *dyn;
2684 size_t dyn_len;
2685 bool do_encryption = session->global->encryption_required;
2686 uint64_t nonce_high = 0;
2687 uint64_t nonce_low = 0;
2689 if (tcon->global->encryption_required) {
2690 do_encryption = true;
2693 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2694 if (state == NULL) {
2695 return NT_STATUS_NO_MEMORY;
2697 state->sconn = sconn;
2699 tf = state->buf + NBT_HDR_SIZE;
2700 tf_len = SMB2_TF_HDR_SIZE;
2701 hdr = tf + tf_len;
2702 body = hdr + SMB2_HDR_BODY;
2703 body_len = 0x18;
2704 dyn = body + body_len;
2705 dyn_len = 0;
2707 if (do_encryption) {
2708 nonce_high = session->nonce_high;
2709 nonce_low = session->nonce_low;
2711 session->nonce_low += 1;
2712 if (session->nonce_low == 0) {
2713 session->nonce_low += 1;
2714 session->nonce_high += 1;
2718 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2719 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2720 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2721 SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
2723 SIVAL(hdr, 0, SMB2_MAGIC);
2724 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2725 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2726 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2727 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2728 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2729 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2730 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2731 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2732 SIVAL(hdr, SMB2_HDR_PID, 0);
2733 SIVAL(hdr, SMB2_HDR_TID, 0);
2734 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2735 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2737 SSVAL(body, 0x00, body_len);
2739 SCVAL(body, 0x02, oplock_level);
2740 SCVAL(body, 0x03, 0); /* reserved */
2741 SIVAL(body, 0x04, 0); /* reserved */
2742 SBVAL(body, 0x08, op->global->open_persistent_id);
2743 SBVAL(body, 0x10, op->global->open_volatile_id);
2745 state->vector[0].iov_base = (void *)state->buf;
2746 state->vector[0].iov_len = NBT_HDR_SIZE;
2748 if (do_encryption) {
2749 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
2750 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
2751 } else {
2752 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
2753 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
2756 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
2757 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
2759 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
2760 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = body_len;
2762 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
2763 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_len;
2765 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2767 if (do_encryption) {
2768 NTSTATUS status;
2769 DATA_BLOB encryption_key = session->global->encryption_key;
2771 status = smb2_signing_encrypt_pdu(encryption_key,
2772 conn->protocol,
2773 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2774 SMBD_SMB2_NUM_IOV_PER_REQ);
2775 if (!NT_STATUS_IS_OK(status)) {
2776 return status;
2780 subreq = tstream_writev_queue_send(state,
2781 sconn->ev_ctx,
2782 sconn->smb2.stream,
2783 sconn->smb2.send_queue,
2784 state->vector,
2785 ARRAY_SIZE(state->vector));
2786 if (subreq == NULL) {
2787 return NT_STATUS_NO_MEMORY;
2789 tevent_req_set_callback(subreq,
2790 smbd_smb2_oplock_break_writev_done,
2791 state);
2793 return NT_STATUS_OK;
2796 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2798 struct smbd_smb2_send_oplock_break_state *state =
2799 tevent_req_callback_data(subreq,
2800 struct smbd_smb2_send_oplock_break_state);
2801 struct smbd_server_connection *sconn = state->sconn;
2802 int ret;
2803 int sys_errno;
2805 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2806 TALLOC_FREE(subreq);
2807 if (ret == -1) {
2808 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2809 smbd_server_connection_terminate(sconn, nt_errstr(status));
2810 return;
2813 TALLOC_FREE(state);
2816 struct smbd_smb2_request_read_state {
2817 struct tevent_context *ev;
2818 struct smbd_server_connection *sconn;
2819 struct smbd_smb2_request *smb2_req;
2820 struct {
2821 uint8_t nbt[NBT_HDR_SIZE];
2822 bool done;
2823 } hdr;
2824 size_t pktlen;
2825 uint8_t *pktbuf;
2828 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2829 void *private_data,
2830 TALLOC_CTX *mem_ctx,
2831 struct iovec **_vector,
2832 size_t *_count);
2833 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2835 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2836 struct tevent_context *ev,
2837 struct smbd_server_connection *sconn)
2839 struct tevent_req *req;
2840 struct smbd_smb2_request_read_state *state;
2841 struct tevent_req *subreq;
2843 req = tevent_req_create(mem_ctx, &state,
2844 struct smbd_smb2_request_read_state);
2845 if (req == NULL) {
2846 return NULL;
2848 state->ev = ev;
2849 state->sconn = sconn;
2851 state->smb2_req = smbd_smb2_request_allocate(state);
2852 if (tevent_req_nomem(state->smb2_req, req)) {
2853 return tevent_req_post(req, ev);
2855 state->smb2_req->sconn = sconn;
2857 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2858 state->ev,
2859 state->sconn->smb2.stream,
2860 state->sconn->smb2.recv_queue,
2861 smbd_smb2_request_next_vector,
2862 state);
2863 if (tevent_req_nomem(subreq, req)) {
2864 return tevent_req_post(req, ev);
2866 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2868 return req;
2871 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2872 void *private_data,
2873 TALLOC_CTX *mem_ctx,
2874 struct iovec **_vector,
2875 size_t *_count)
2877 struct smbd_smb2_request_read_state *state =
2878 talloc_get_type_abort(private_data,
2879 struct smbd_smb2_request_read_state);
2880 struct iovec *vector;
2882 if (state->pktlen > 0) {
2883 /* if there're no remaining bytes, we're done */
2884 *_vector = NULL;
2885 *_count = 0;
2886 return 0;
2889 if (!state->hdr.done) {
2891 * first we need to get the NBT header
2893 vector = talloc_array(mem_ctx, struct iovec, 1);
2894 if (vector == NULL) {
2895 return -1;
2898 vector[0].iov_base = (void *)state->hdr.nbt;
2899 vector[0].iov_len = NBT_HDR_SIZE;
2901 *_vector = vector;
2902 *_count = 1;
2904 state->hdr.done = true;
2905 return 0;
2909 * Now we analyze the NBT header
2911 state->pktlen = smb2_len(state->hdr.nbt);
2913 if (state->pktlen == 0) {
2914 /* if there're no remaining bytes, we're done */
2915 *_vector = NULL;
2916 *_count = 0;
2917 return 0;
2920 state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
2921 if (state->pktbuf == NULL) {
2922 return -1;
2925 vector = talloc_array(mem_ctx, struct iovec, 1);
2926 if (vector == NULL) {
2927 return -1;
2930 vector[0].iov_base = (void *)state->pktbuf;
2931 vector[0].iov_len = state->pktlen;
2933 *_vector = vector;
2934 *_count = 1;
2935 return 0;
2938 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2940 struct tevent_req *req =
2941 tevent_req_callback_data(subreq,
2942 struct tevent_req);
2943 struct smbd_smb2_request_read_state *state =
2944 tevent_req_data(req,
2945 struct smbd_smb2_request_read_state);
2946 int ret;
2947 int sys_errno;
2948 NTSTATUS status;
2949 NTTIME now;
2951 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2952 TALLOC_FREE(subreq);
2953 if (ret == -1) {
2954 status = map_nt_error_from_unix(sys_errno);
2955 tevent_req_nterror(req, status);
2956 return;
2959 if (state->hdr.nbt[0] != 0x00) {
2960 DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
2961 state->hdr.nbt[0]));
2963 ZERO_STRUCT(state->hdr);
2964 TALLOC_FREE(state->pktbuf);
2965 state->pktlen = 0;
2967 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2968 state->ev,
2969 state->sconn->smb2.stream,
2970 state->sconn->smb2.recv_queue,
2971 smbd_smb2_request_next_vector,
2972 state);
2973 if (tevent_req_nomem(subreq, req)) {
2974 return;
2976 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2977 return;
2980 state->smb2_req->request_time = timeval_current();
2981 now = timeval_to_nttime(&state->smb2_req->request_time);
2983 status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
2984 now,
2985 state->pktbuf,
2986 state->pktlen,
2987 state->smb2_req,
2988 &state->smb2_req->in.vector,
2989 &state->smb2_req->in.vector_count);
2990 if (tevent_req_nterror(req, status)) {
2991 return;
2994 state->smb2_req->current_idx = 1;
2996 tevent_req_done(req);
2999 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
3000 TALLOC_CTX *mem_ctx,
3001 struct smbd_smb2_request **_smb2_req)
3003 struct smbd_smb2_request_read_state *state =
3004 tevent_req_data(req,
3005 struct smbd_smb2_request_read_state);
3006 NTSTATUS status;
3008 if (tevent_req_is_nterror(req, &status)) {
3009 tevent_req_received(req);
3010 return status;
3013 *_smb2_req = talloc_move(mem_ctx, &state->smb2_req);
3014 tevent_req_received(req);
3015 return NT_STATUS_OK;
3018 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
3020 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
3022 size_t max_send_queue_len;
3023 size_t cur_send_queue_len;
3024 struct tevent_req *subreq;
3026 if (sconn->smb2.compound_related_in_progress) {
3028 * Can't read another until the related
3029 * compound is done.
3031 return NT_STATUS_OK;
3034 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
3036 * if there is already a smbd_smb2_request_read
3037 * pending, we are done.
3039 return NT_STATUS_OK;
3042 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
3043 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
3045 if (cur_send_queue_len > max_send_queue_len) {
3047 * if we have a lot of requests to send,
3048 * we wait until they are on the wire until we
3049 * ask for the next request.
3051 return NT_STATUS_OK;
3054 /* ask for the next request */
3055 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
3056 if (subreq == NULL) {
3057 return NT_STATUS_NO_MEMORY;
3059 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
3061 return NT_STATUS_OK;
3064 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
3065 uint8_t *inbuf, size_t size)
3067 NTSTATUS status;
3068 struct smbd_smb2_request *req = NULL;
3070 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
3071 (unsigned int)size));
3073 status = smbd_initialize_smb2(sconn);
3074 if (!NT_STATUS_IS_OK(status)) {
3075 smbd_server_connection_terminate(sconn, nt_errstr(status));
3076 return;
3079 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
3080 if (!NT_STATUS_IS_OK(status)) {
3081 smbd_server_connection_terminate(sconn, nt_errstr(status));
3082 return;
3085 status = smbd_smb2_request_validate(req);
3086 if (!NT_STATUS_IS_OK(status)) {
3087 smbd_server_connection_terminate(sconn, nt_errstr(status));
3088 return;
3091 status = smbd_smb2_request_setup_out(req);
3092 if (!NT_STATUS_IS_OK(status)) {
3093 smbd_server_connection_terminate(sconn, nt_errstr(status));
3094 return;
3097 status = smbd_smb2_request_dispatch(req);
3098 if (!NT_STATUS_IS_OK(status)) {
3099 smbd_server_connection_terminate(sconn, nt_errstr(status));
3100 return;
3103 status = smbd_smb2_request_next_incoming(sconn);
3104 if (!NT_STATUS_IS_OK(status)) {
3105 smbd_server_connection_terminate(sconn, nt_errstr(status));
3106 return;
3109 sconn->num_requests++;
3112 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
3114 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
3115 struct smbd_server_connection);
3116 NTSTATUS status;
3117 struct smbd_smb2_request *req = NULL;
3119 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
3120 TALLOC_FREE(subreq);
3121 if (!NT_STATUS_IS_OK(status)) {
3122 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
3123 nt_errstr(status)));
3124 smbd_server_connection_terminate(sconn, nt_errstr(status));
3125 return;
3128 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
3129 req->current_idx, req->in.vector_count));
3131 status = smbd_smb2_request_validate(req);
3132 if (!NT_STATUS_IS_OK(status)) {
3133 smbd_server_connection_terminate(sconn, nt_errstr(status));
3134 return;
3137 status = smbd_smb2_request_setup_out(req);
3138 if (!NT_STATUS_IS_OK(status)) {
3139 smbd_server_connection_terminate(sconn, nt_errstr(status));
3140 return;
3143 status = smbd_smb2_request_dispatch(req);
3144 if (!NT_STATUS_IS_OK(status)) {
3145 smbd_server_connection_terminate(sconn, nt_errstr(status));
3146 return;
3149 status = smbd_smb2_request_next_incoming(sconn);
3150 if (!NT_STATUS_IS_OK(status)) {
3151 smbd_server_connection_terminate(sconn, nt_errstr(status));
3152 return;
3155 sconn->num_requests++;
3157 /* The timeout_processing function isn't run nearly
3158 often enough to implement 'max log size' without
3159 overrunning the size of the file by many megabytes.
3160 This is especially true if we are running at debug
3161 level 10. Checking every 50 SMB2s is a nice
3162 tradeoff of performance vs log file size overrun. */
3164 if ((sconn->num_requests % 50) == 0 &&
3165 need_to_check_log_size()) {
3166 change_to_root_user();
3167 check_log_size();