s3:smb2_server: avoid segfault in smbd_smb2_request_pending_queue()
[Samba/gebeck_regimport.git] / source3 / smbd / smb2_server.c
blobdcaefb16890f03d66d2aee144098b799f6c98c6e
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 verify high credit charge.
762 * TODO: scale up depending one 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);
783 SMB_ASSERT(sconn->smb2.max_credits >= credit_charge);
785 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
787 * In case we already send an async interim
788 * response, we should not grant
789 * credits on the final response.
791 credits_granted = 0;
792 } else if (credits_requested > 0) {
793 uint16_t additional_max = 0;
794 uint16_t additional_credits = credits_requested - 1;
796 switch (cmd) {
797 case SMB2_OP_NEGPROT:
798 break;
799 case SMB2_OP_SESSSETUP:
801 * Windows 2012 RC1 starts to grant
802 * additional credits
803 * with a successful session setup
805 if (NT_STATUS_IS_OK(out_status)) {
806 additional_max = 32;
808 break;
809 default:
811 * We match windows and only grant additional credits
812 * in chunks of 32.
814 additional_max = 32;
815 break;
818 additional_credits = MIN(additional_credits, additional_max);
820 credits_granted = credit_charge + additional_credits;
821 } else if (sconn->smb2.credits_granted == 0) {
823 * Make sure the client has always at least one credit
825 credits_granted = 1;
829 * sequence numbers should not wrap
831 * 1. calculate the possible credits until
832 * the sequence numbers start to wrap on 64-bit.
834 * 2. UINT64_MAX is used for Break Notifications.
836 * 2. truncate the possible credits to the maximum
837 * credits we want to grant to the client in total.
839 * 3. remove the range we'll already granted to the client
840 * this makes sure the client consumes the lowest sequence
841 * number, before we can grant additional credits.
843 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
844 if (credits_possible > 0) {
845 /* remove UINT64_MAX */
846 credits_possible -= 1;
848 credits_possible = MIN(credits_possible, current_max_credits);
849 credits_possible -= sconn->smb2.seqnum_range;
851 credits_granted = MIN(credits_granted, credits_possible);
853 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
854 sconn->smb2.credits_granted += credits_granted;
855 sconn->smb2.seqnum_range += credits_granted;
857 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
858 "granted %u, current possible/max %u/%u, "
859 "total granted/max/low/range %u/%u/%llu/%u\n",
860 (unsigned int)credits_requested,
861 (unsigned int)credit_charge,
862 (unsigned int)credits_granted,
863 (unsigned int)credits_possible,
864 (unsigned int)current_max_credits,
865 (unsigned int)sconn->smb2.credits_granted,
866 (unsigned int)sconn->smb2.max_credits,
867 (unsigned long long)sconn->smb2.seqnum_low,
868 (unsigned int)sconn->smb2.seqnum_range));
871 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
872 struct smbd_smb2_request *outreq)
874 int count, idx;
875 uint16_t total_credits = 0;
877 count = outreq->out.vector_count;
879 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
880 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
881 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
882 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
884 smb2_set_operation_credit(outreq->sconn, inhdr_v, outhdr_v);
886 /* To match Windows, count up what we
887 just granted. */
888 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
889 /* Set to zero in all but the last reply. */
890 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
891 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
892 } else {
893 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
898 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
900 struct iovec *vector;
901 int count;
902 int idx;
904 count = req->in.vector_count;
905 vector = talloc_zero_array(req, struct iovec, count);
906 if (vector == NULL) {
907 return NT_STATUS_NO_MEMORY;
910 vector[0].iov_base = req->out.nbt_hdr;
911 vector[0].iov_len = 4;
912 SIVAL(req->out.nbt_hdr, 0, 0);
914 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
915 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
916 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
917 uint8_t *outhdr = NULL;
918 uint8_t *outbody = NULL;
919 uint32_t next_command_ofs = 0;
920 struct iovec *current = &vector[idx];
922 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
923 /* we have a next command -
924 * setup for the error case. */
925 next_command_ofs = SMB2_HDR_BODY + 9;
928 outhdr = talloc_zero_array(vector, uint8_t,
929 OUTVEC_ALLOC_SIZE);
930 if (outhdr == NULL) {
931 return NT_STATUS_NO_MEMORY;
934 outbody = outhdr + SMB2_HDR_BODY;
937 * SMBD_SMB2_TF_IOV_OFS might be used later
939 current[SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
940 current[SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
942 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
943 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
945 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
946 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
948 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
949 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
951 /* setup the SMB2 header */
952 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
953 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
954 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
955 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
956 SIVAL(outhdr, SMB2_HDR_STATUS,
957 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
958 SSVAL(outhdr, SMB2_HDR_OPCODE,
959 SVAL(inhdr, SMB2_HDR_OPCODE));
960 SIVAL(outhdr, SMB2_HDR_FLAGS,
961 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
962 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
963 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
964 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
965 SIVAL(outhdr, SMB2_HDR_PID,
966 IVAL(inhdr, SMB2_HDR_PID));
967 SIVAL(outhdr, SMB2_HDR_TID,
968 IVAL(inhdr, SMB2_HDR_TID));
969 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
970 BVAL(inhdr, SMB2_HDR_SESSION_ID));
971 memcpy(outhdr + SMB2_HDR_SIGNATURE,
972 inhdr + SMB2_HDR_SIGNATURE, 16);
974 /* setup error body header */
975 SSVAL(outbody, 0x00, 0x08 + 1);
976 SSVAL(outbody, 0x02, 0);
977 SIVAL(outbody, 0x04, 0);
980 req->out.vector = vector;
981 req->out.vector_count = count;
983 /* setup the length of the NBT packet */
984 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
986 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
988 return NT_STATUS_OK;
991 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
992 const char *reason,
993 const char *location)
995 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
996 reason, location));
997 exit_server_cleanly(reason);
1000 static bool dup_smb2_vec4(TALLOC_CTX *ctx,
1001 struct iovec *outvec,
1002 const struct iovec *srcvec)
1004 const uint8_t *srctf;
1005 size_t srctf_len;
1006 const uint8_t *srchdr;
1007 size_t srchdr_len;
1008 const uint8_t *srcbody;
1009 size_t srcbody_len;
1010 const uint8_t *expected_srcbody;
1011 const uint8_t *srcdyn;
1012 size_t srcdyn_len;
1013 const uint8_t *expected_srcdyn;
1014 uint8_t *dsttf;
1015 uint8_t *dsthdr;
1016 uint8_t *dstbody;
1017 uint8_t *dstdyn;
1019 srctf = (const uint8_t *)srcvec[SMBD_SMB2_TF_IOV_OFS].iov_base;
1020 srctf_len = srcvec[SMBD_SMB2_TF_IOV_OFS].iov_len;
1021 srchdr = (const uint8_t *)srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base;
1022 srchdr_len = srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_len;
1023 srcbody = (const uint8_t *)srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_base;
1024 srcbody_len = srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_len;
1025 expected_srcbody = srchdr + SMB2_HDR_BODY;
1026 srcdyn = (const uint8_t *)srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_base;
1027 srcdyn_len = srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_len;
1028 expected_srcdyn = srcbody + 8;
1030 if ((srctf_len != SMB2_TF_HDR_SIZE) && (srctf_len != 0)) {
1031 return false;
1034 if (srchdr_len != SMB2_HDR_BODY) {
1035 return false;
1038 if (srctf_len == SMB2_TF_HDR_SIZE) {
1039 dsttf = talloc_memdup(ctx, srctf, SMB2_TF_HDR_SIZE);
1040 if (dsttf == NULL) {
1041 return false;
1043 } else {
1044 dsttf = NULL;
1046 outvec[SMBD_SMB2_TF_IOV_OFS].iov_base = (void *)dsttf;
1047 outvec[SMBD_SMB2_TF_IOV_OFS].iov_len = srctf_len;
1049 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
1050 * be allocated with size OUTVEC_ALLOC_SIZE. */
1052 dsthdr = talloc_memdup(ctx, srchdr, OUTVEC_ALLOC_SIZE);
1053 if (dsthdr == NULL) {
1054 return false;
1056 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)dsthdr;
1057 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1060 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
1061 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
1062 * then duplicate this. Else use talloc_memdup().
1065 if ((srcbody == expected_srcbody) && (srcbody_len == 8)) {
1066 dstbody = dsthdr + SMB2_HDR_BODY;
1067 } else {
1068 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1069 if (dstbody == NULL) {
1070 return false;
1073 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)dstbody;
1074 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_len = srcbody_len;
1077 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1078 * pointing to
1079 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1080 * then duplicate this. Else use talloc_memdup().
1083 if ((srcdyn == expected_srcdyn) && (srcdyn_len == 1)) {
1084 dstdyn = dsthdr + SMB2_HDR_BODY + 8;
1085 } else if (srcdyn == NULL) {
1086 dstdyn = NULL;
1087 } else {
1088 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1089 if (dstdyn == NULL) {
1090 return false;
1093 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1094 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
1096 return true;
1099 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
1101 struct smbd_smb2_request *newreq = NULL;
1102 struct iovec *outvec = NULL;
1103 int count = req->out.vector_count;
1104 int i;
1106 newreq = smbd_smb2_request_allocate(req->sconn);
1107 if (!newreq) {
1108 return NULL;
1111 newreq->sconn = req->sconn;
1112 newreq->session = req->session;
1113 newreq->do_encryption = req->do_encryption;
1114 newreq->do_signing = req->do_signing;
1115 newreq->current_idx = req->current_idx;
1117 outvec = talloc_zero_array(newreq, struct iovec, count);
1118 if (!outvec) {
1119 TALLOC_FREE(newreq);
1120 return NULL;
1122 newreq->out.vector = outvec;
1123 newreq->out.vector_count = count;
1125 /* Setup the outvec's identically to req. */
1126 outvec[0].iov_base = newreq->out.nbt_hdr;
1127 outvec[0].iov_len = 4;
1128 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1130 /* Setup the vectors identically to the ones in req. */
1131 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1132 if (!dup_smb2_vec4(outvec, &outvec[i], &req->out.vector[i])) {
1133 break;
1137 if (i < count) {
1138 /* Alloc failed. */
1139 TALLOC_FREE(newreq);
1140 return NULL;
1143 smb2_setup_nbt_length(newreq->out.vector,
1144 newreq->out.vector_count);
1146 return newreq;
1149 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
1151 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1153 struct smbXsrv_connection *conn = req->sconn->conn;
1154 int first_idx = 1;
1155 struct iovec *firsttf = NULL;
1156 struct iovec *outhdr_v = NULL;
1157 uint8_t *outhdr = NULL;
1158 struct smbd_smb2_request *nreq = NULL;
1159 NTSTATUS status;
1161 /* Create a new smb2 request we'll use
1162 for the interim return. */
1163 nreq = dup_smb2_req(req);
1164 if (!nreq) {
1165 return NT_STATUS_NO_MEMORY;
1168 /* Lose the last X out vectors. They're the
1169 ones we'll be using for the async reply. */
1170 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1172 smb2_setup_nbt_length(nreq->out.vector,
1173 nreq->out.vector_count);
1175 /* Step back to the previous reply. */
1176 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1177 firsttf = SMBD_SMB2_IDX_TF_IOV(nreq,out,first_idx);
1178 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1179 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1180 /* And end the chain. */
1181 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1183 /* Calculate outgoing credits */
1184 smb2_calculate_credits(req, nreq);
1186 if (DEBUGLEVEL >= 10) {
1187 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1188 (unsigned int)nreq->current_idx );
1189 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1190 (unsigned int)nreq->out.vector_count );
1191 print_req_vectors(nreq);
1195 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1196 * we need to sign/encrypt here with the last/first key we remembered
1198 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
1199 status = smb2_signing_encrypt_pdu(req->first_key,
1200 conn->protocol,
1201 firsttf,
1202 nreq->out.vector_count - first_idx);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 return status;
1206 } else if (req->last_key.length > 0) {
1207 status = smb2_signing_sign_pdu(req->last_key,
1208 conn->protocol,
1209 outhdr_v,
1210 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1211 if (!NT_STATUS_IS_OK(status)) {
1212 return status;
1216 nreq->subreq = tstream_writev_queue_send(nreq,
1217 nreq->sconn->ev_ctx,
1218 nreq->sconn->smb2.stream,
1219 nreq->sconn->smb2.send_queue,
1220 nreq->out.vector,
1221 nreq->out.vector_count);
1223 if (nreq->subreq == NULL) {
1224 return NT_STATUS_NO_MEMORY;
1227 tevent_req_set_callback(nreq->subreq,
1228 smbd_smb2_request_writev_done,
1229 nreq);
1231 return NT_STATUS_OK;
1234 struct smbd_smb2_request_pending_state {
1235 struct smbd_server_connection *sconn;
1236 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1];
1237 struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ];
1240 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
1242 struct smbd_smb2_request_pending_state *state =
1243 tevent_req_callback_data(subreq,
1244 struct smbd_smb2_request_pending_state);
1245 struct smbd_server_connection *sconn = state->sconn;
1246 int ret;
1247 int sys_errno;
1249 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1250 TALLOC_FREE(subreq);
1251 if (ret == -1) {
1252 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1253 smbd_server_connection_terminate(sconn, nt_errstr(status));
1254 return;
1257 TALLOC_FREE(state);
1260 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1261 struct tevent_timer *te,
1262 struct timeval current_time,
1263 void *private_data);
1265 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1266 struct tevent_req *subreq,
1267 uint32_t defer_time)
1269 NTSTATUS status;
1270 int idx = req->current_idx;
1271 struct timeval defer_endtime;
1272 uint8_t *outhdr = NULL;
1273 uint32_t flags;
1275 if (!tevent_req_is_in_progress(subreq)) {
1276 return NT_STATUS_OK;
1279 req->subreq = subreq;
1280 subreq = NULL;
1282 if (req->async_te) {
1283 /* We're already async. */
1284 return NT_STATUS_OK;
1287 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1288 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1289 if (flags & SMB2_HDR_FLAG_ASYNC) {
1290 /* We're already async. */
1291 return NT_STATUS_OK;
1294 if (req->in.vector_count > idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1296 * We're trying to go async in a compound
1297 * request chain. This is not allowed.
1298 * Cancel the outstanding request.
1300 bool ok = tevent_req_cancel(req->subreq);
1301 if (ok) {
1302 return NT_STATUS_OK;
1304 TALLOC_FREE(req->subreq);
1305 return smbd_smb2_request_error(req,
1306 NT_STATUS_INTERNAL_ERROR);
1309 if (DEBUGLEVEL >= 10) {
1310 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1311 (unsigned int)req->current_idx );
1312 print_req_vectors(req);
1315 if (req->out.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ)) {
1317 * This is a compound reply. We
1318 * must do an interim response
1319 * followed by the async response
1320 * to match W2K8R2.
1322 status = smb2_send_async_interim_response(req);
1323 if (!NT_STATUS_IS_OK(status)) {
1324 return status;
1326 data_blob_clear_free(&req->first_key);
1329 * We're splitting off the last SMB2
1330 * request in a compound set, and the
1331 * smb2_send_async_interim_response()
1332 * call above just sent all the replies
1333 * for the previous SMB2 requests in
1334 * this compound set. So we're no longer
1335 * in the "compound_related_in_progress"
1336 * state, and this is no longer a compound
1337 * request.
1339 req->compound_related = false;
1340 req->sconn->smb2.compound_related_in_progress = false;
1342 req->current_idx = 1;
1344 /* Re-arrange the in.vectors. */
1345 memmove(&req->in.vector[req->current_idx],
1346 &req->in.vector[idx],
1347 sizeof(req->in.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1348 req->in.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1350 /* Re-arrange the out.vectors. */
1351 memmove(&req->out.vector[req->current_idx],
1352 &req->out.vector[idx],
1353 sizeof(req->out.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1354 req->out.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1356 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1357 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1358 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1360 data_blob_clear_free(&req->last_key);
1362 defer_endtime = timeval_current_ofs_usec(defer_time);
1363 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1364 req, defer_endtime,
1365 smbd_smb2_request_pending_timer,
1366 req);
1367 if (req->async_te == NULL) {
1368 return NT_STATUS_NO_MEMORY;
1371 return NT_STATUS_OK;
1374 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1375 struct tevent_timer *te,
1376 struct timeval current_time,
1377 void *private_data)
1379 struct smbd_smb2_request *req =
1380 talloc_get_type_abort(private_data,
1381 struct smbd_smb2_request);
1382 struct smbd_smb2_request_pending_state *state = NULL;
1383 uint8_t *outhdr = NULL;
1384 const uint8_t *inhdr = NULL;
1385 uint8_t *tf = NULL;
1386 size_t tf_len = 0;
1387 uint8_t *hdr = NULL;
1388 uint8_t *body = NULL;
1389 uint8_t *dyn = NULL;
1390 uint32_t flags = 0;
1391 uint64_t session_id = 0;
1392 uint64_t message_id = 0;
1393 uint64_t nonce_high = 0;
1394 uint64_t nonce_low = 0;
1395 uint64_t async_id = 0;
1396 struct tevent_req *subreq = NULL;
1398 TALLOC_FREE(req->async_te);
1400 /* Ensure our final reply matches the interim one. */
1401 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1402 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1403 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1404 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1405 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1407 async_id = message_id; /* keep it simple for now... */
1409 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1410 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1412 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1413 "going async\n",
1414 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1415 (unsigned long long)async_id ));
1418 * What we send is identical to a smbd_smb2_request_error
1419 * packet with an error status of STATUS_PENDING. Make use
1420 * of this fact sometime when refactoring. JRA.
1423 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1424 if (state == NULL) {
1425 smbd_server_connection_terminate(req->sconn,
1426 nt_errstr(NT_STATUS_NO_MEMORY));
1427 return;
1429 state->sconn = req->sconn;
1431 tf = state->buf + NBT_HDR_SIZE;
1432 tf_len = SMB2_TF_HDR_SIZE;
1434 hdr = tf + SMB2_TF_HDR_SIZE;
1435 body = hdr + SMB2_HDR_BODY;
1436 dyn = body + 8;
1438 if (req->do_encryption) {
1439 struct smbXsrv_session *x = req->session;
1441 nonce_high = x->nonce_high;
1442 nonce_low = x->nonce_low;
1444 x->nonce_low += 1;
1445 if (x->nonce_low == 0) {
1446 x->nonce_low += 1;
1447 x->nonce_high += 1;
1451 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1452 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1453 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1454 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1456 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1457 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1458 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1459 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1460 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1462 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1463 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1464 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1465 SBVAL(hdr, SMB2_HDR_PID, async_id);
1466 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1467 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1468 memcpy(hdr+SMB2_HDR_SIGNATURE,
1469 outhdr+SMB2_HDR_SIGNATURE, 16);
1471 SSVAL(body, 0x00, 0x08 + 1);
1473 SCVAL(body, 0x02, 0);
1474 SCVAL(body, 0x03, 0);
1475 SIVAL(body, 0x04, 0);
1476 /* Match W2K8R2... */
1477 SCVAL(dyn, 0x00, 0x21);
1479 state->vector[0].iov_base = (void *)state->buf;
1480 state->vector[0].iov_len = NBT_HDR_SIZE;
1482 if (req->do_encryption) {
1483 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1484 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1485 } else {
1486 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1487 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1490 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1491 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1493 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1494 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1496 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1497 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1499 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1501 /* Ensure we correctly go through crediting. Grant
1502 the credits now, and zero credits on the final
1503 response. */
1504 smb2_set_operation_credit(req->sconn,
1505 SMBD_SMB2_IN_HDR_IOV(req),
1506 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1508 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1510 if (DEBUGLVL(10)) {
1511 int i;
1513 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1514 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1515 (unsigned int)i,
1516 (unsigned int)ARRAY_SIZE(state->vector),
1517 (unsigned int)state->vector[i].iov_len);
1521 if (req->do_encryption) {
1522 NTSTATUS status;
1523 struct smbXsrv_session *x = req->session;
1524 struct smbXsrv_connection *conn = x->connection;
1525 DATA_BLOB encryption_key = x->global->encryption_key;
1527 status = smb2_signing_encrypt_pdu(encryption_key,
1528 conn->protocol,
1529 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1530 SMBD_SMB2_NUM_IOV_PER_REQ);
1531 if (!NT_STATUS_IS_OK(status)) {
1532 smbd_server_connection_terminate(req->sconn,
1533 nt_errstr(status));
1534 return;
1536 } else if (req->do_signing) {
1537 NTSTATUS status;
1538 struct smbXsrv_session *x = req->session;
1539 struct smbXsrv_connection *conn = x->connection;
1540 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1542 status = smb2_signing_sign_pdu(signing_key,
1543 conn->protocol,
1544 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1545 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1546 if (!NT_STATUS_IS_OK(status)) {
1547 smbd_server_connection_terminate(req->sconn,
1548 nt_errstr(status));
1549 return;
1553 subreq = tstream_writev_queue_send(state,
1554 state->sconn->ev_ctx,
1555 state->sconn->smb2.stream,
1556 state->sconn->smb2.send_queue,
1557 state->vector,
1558 ARRAY_SIZE(state->vector));
1559 if (subreq == NULL) {
1560 smbd_server_connection_terminate(state->sconn,
1561 nt_errstr(NT_STATUS_NO_MEMORY));
1562 return;
1564 tevent_req_set_callback(subreq,
1565 smbd_smb2_request_pending_writev_done,
1566 state);
1569 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1571 struct smbd_server_connection *sconn = req->sconn;
1572 struct smbd_smb2_request *cur;
1573 const uint8_t *inhdr;
1574 uint32_t flags;
1575 uint64_t search_message_id;
1576 uint64_t search_async_id;
1577 uint64_t found_id;
1579 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1581 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1582 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1583 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1586 * we don't need the request anymore
1587 * cancel requests never have a response
1589 DLIST_REMOVE(req->sconn->smb2.requests, req);
1590 TALLOC_FREE(req);
1592 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1593 const uint8_t *outhdr;
1594 uint64_t message_id;
1595 uint64_t async_id;
1597 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1599 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1600 async_id = BVAL(outhdr, SMB2_HDR_PID);
1602 if (flags & SMB2_HDR_FLAG_ASYNC) {
1603 if (search_async_id == async_id) {
1604 found_id = async_id;
1605 break;
1607 } else {
1608 if (search_message_id == message_id) {
1609 found_id = message_id;
1610 break;
1615 if (cur && cur->subreq) {
1616 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1617 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1618 "cancel opcode[%s] mid %llu\n",
1619 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1620 (unsigned long long)found_id ));
1621 tevent_req_cancel(cur->subreq);
1624 return NT_STATUS_OK;
1627 /*************************************************************
1628 Ensure an incoming tid is a valid one for us to access.
1629 Change to the associated uid credentials and chdir to the
1630 valid tid directory.
1631 *************************************************************/
1633 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1635 const uint8_t *inhdr;
1636 uint32_t in_flags;
1637 uint32_t in_tid;
1638 struct smbXsrv_tcon *tcon;
1639 NTSTATUS status;
1640 NTTIME now = timeval_to_nttime(&req->request_time);
1642 req->tcon = NULL;
1644 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1646 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1647 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1649 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1650 in_tid = req->last_tid;
1653 req->last_tid = 0;
1655 status = smb2srv_tcon_lookup(req->session,
1656 in_tid, now, &tcon);
1657 if (!NT_STATUS_IS_OK(status)) {
1658 return status;
1661 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1662 return NT_STATUS_ACCESS_DENIED;
1665 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1666 if (!set_current_service(tcon->compat, 0, true)) {
1667 return NT_STATUS_ACCESS_DENIED;
1670 req->tcon = tcon;
1671 req->last_tid = in_tid;
1673 return NT_STATUS_OK;
1676 /*************************************************************
1677 Ensure an incoming session_id is a valid one for us to access.
1678 *************************************************************/
1680 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1682 const uint8_t *inhdr;
1683 uint32_t in_flags;
1684 uint16_t in_opcode;
1685 uint64_t in_session_id;
1686 struct smbXsrv_session *session = NULL;
1687 struct auth_session_info *session_info;
1688 NTSTATUS status;
1689 NTTIME now = timeval_to_nttime(&req->request_time);
1691 req->session = NULL;
1692 req->tcon = NULL;
1694 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1696 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1697 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1698 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1700 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1701 in_session_id = req->last_session_id;
1704 req->last_session_id = 0;
1706 /* lookup an existing session */
1707 status = smb2srv_session_lookup(req->sconn->conn,
1708 in_session_id, now,
1709 &session);
1710 if (session) {
1711 req->session = session;
1712 req->last_session_id = in_session_id;
1714 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1715 switch (in_opcode) {
1716 case SMB2_OP_SESSSETUP:
1717 status = NT_STATUS_OK;
1718 break;
1719 default:
1720 break;
1723 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1724 switch (in_opcode) {
1725 case SMB2_OP_TCON:
1726 case SMB2_OP_CREATE:
1727 case SMB2_OP_GETINFO:
1728 case SMB2_OP_SETINFO:
1729 return NT_STATUS_INVALID_HANDLE;
1730 default:
1732 * Notice the check for
1733 * (session_info == NULL)
1734 * below.
1736 status = NT_STATUS_OK;
1737 break;
1740 if (!NT_STATUS_IS_OK(status)) {
1741 return status;
1744 session_info = session->global->auth_session_info;
1745 if (session_info == NULL) {
1746 return NT_STATUS_INVALID_HANDLE;
1749 set_current_user_info(session_info->unix_info->sanitized_username,
1750 session_info->unix_info->unix_name,
1751 session_info->info->domain_name);
1753 return NT_STATUS_OK;
1756 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1757 uint32_t data_length)
1759 uint16_t needed_charge;
1760 uint16_t credit_charge = 1;
1761 const uint8_t *inhdr;
1763 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1765 if (req->sconn->smb2.supports_multicredit) {
1766 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1767 credit_charge = MAX(credit_charge, 1);
1770 needed_charge = (data_length - 1)/ 65536 + 1;
1772 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1773 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1774 credit_charge, needed_charge));
1776 if (needed_charge > credit_charge) {
1777 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1778 credit_charge, needed_charge));
1779 return NT_STATUS_INVALID_PARAMETER;
1782 return NT_STATUS_OK;
1785 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1786 size_t expected_body_size)
1788 struct iovec *inhdr_v;
1789 const uint8_t *inhdr;
1790 uint16_t opcode;
1791 const uint8_t *inbody;
1792 size_t body_size;
1793 size_t min_dyn_size = expected_body_size & 0x00000001;
1794 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1797 * The following should be checked already.
1799 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1800 return NT_STATUS_INTERNAL_ERROR;
1802 if (req->current_idx > max_idx) {
1803 return NT_STATUS_INTERNAL_ERROR;
1806 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1807 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1808 return NT_STATUS_INTERNAL_ERROR;
1810 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1811 return NT_STATUS_INTERNAL_ERROR;
1814 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1815 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1817 switch (opcode) {
1818 case SMB2_OP_IOCTL:
1819 case SMB2_OP_GETINFO:
1820 min_dyn_size = 0;
1821 break;
1825 * Now check the expected body size,
1826 * where the last byte might be in the
1827 * dynamic section..
1829 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1830 return NT_STATUS_INVALID_PARAMETER;
1832 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1833 return NT_STATUS_INVALID_PARAMETER;
1836 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1838 body_size = SVAL(inbody, 0x00);
1839 if (body_size != expected_body_size) {
1840 return NT_STATUS_INVALID_PARAMETER;
1843 return NT_STATUS_OK;
1846 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1848 struct smbXsrv_connection *conn = req->sconn->conn;
1849 const struct smbd_smb2_dispatch_table *call = NULL;
1850 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1851 const uint8_t *inhdr;
1852 uint16_t opcode;
1853 uint32_t flags;
1854 uint64_t mid;
1855 NTSTATUS status;
1856 NTSTATUS session_status;
1857 uint32_t allowed_flags;
1858 NTSTATUS return_value;
1859 struct smbXsrv_session *x = NULL;
1860 bool signing_required = false;
1861 bool encryption_required = false;
1863 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1865 /* TODO: verify more things */
1867 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1868 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1869 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1870 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1871 smb2_opcode_name(opcode),
1872 (unsigned long long)mid));
1874 if (conn->protocol >= PROTOCOL_SMB2_02) {
1876 * once the protocol is negotiated
1877 * SMB2_OP_NEGPROT is not allowed anymore
1879 if (opcode == SMB2_OP_NEGPROT) {
1880 /* drop the connection */
1881 return NT_STATUS_INVALID_PARAMETER;
1883 } else {
1885 * if the protocol is not negotiated yet
1886 * only SMB2_OP_NEGPROT is allowed.
1888 if (opcode != SMB2_OP_NEGPROT) {
1889 /* drop the connection */
1890 return NT_STATUS_INVALID_PARAMETER;
1895 * Check if the client provided a valid session id,
1896 * if so smbd_smb2_request_check_session() calls
1897 * set_current_user_info().
1899 * As some command don't require a valid session id
1900 * we defer the check of the session_status
1902 session_status = smbd_smb2_request_check_session(req);
1903 x = req->session;
1904 if (x != NULL) {
1905 signing_required = x->global->signing_required;
1906 encryption_required = x->global->encryption_required;
1908 if (opcode == SMB2_OP_SESSSETUP &&
1909 x->global->channels[0].signing_key.length) {
1910 signing_required = true;
1914 req->do_signing = false;
1915 req->do_encryption = false;
1916 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1917 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1918 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1920 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1921 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1922 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1923 (unsigned long long)x->global->session_wire_id,
1924 (unsigned long long)tf_session_id));
1926 * TODO: windows allows this...
1927 * should we drop the connection?
1929 * For now we just return ACCESS_DENIED
1930 * (Windows clients never trigger this)
1931 * and wait for an update of [MS-SMB2].
1933 return smbd_smb2_request_error(req,
1934 NT_STATUS_ACCESS_DENIED);
1937 req->do_encryption = true;
1940 if (encryption_required && !req->do_encryption) {
1941 return smbd_smb2_request_error(req,
1942 NT_STATUS_ACCESS_DENIED);
1945 call = smbd_smb2_call(opcode);
1946 if (call == NULL) {
1947 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1950 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1951 SMB2_HDR_FLAG_SIGNED |
1952 SMB2_HDR_FLAG_DFS;
1953 if (opcode == SMB2_OP_CANCEL) {
1954 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1956 if ((flags & ~allowed_flags) != 0) {
1957 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1960 if (flags & SMB2_HDR_FLAG_CHAINED) {
1962 * This check is mostly for giving the correct error code
1963 * for compounded requests.
1965 if (!NT_STATUS_IS_OK(session_status)) {
1966 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1968 } else {
1969 req->compat_chain_fsp = NULL;
1972 if (req->do_encryption) {
1973 signing_required = false;
1974 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1975 DATA_BLOB signing_key;
1977 if (x == NULL) {
1978 return smbd_smb2_request_error(
1979 req, NT_STATUS_ACCESS_DENIED);
1982 signing_key = x->global->channels[0].signing_key;
1985 * If we have a signing key, we should
1986 * sign the response
1988 if (signing_key.length > 0) {
1989 req->do_signing = true;
1992 status = smb2_signing_check_pdu(signing_key,
1993 conn->protocol,
1994 SMBD_SMB2_IN_HDR_IOV(req),
1995 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1996 if (!NT_STATUS_IS_OK(status)) {
1997 return smbd_smb2_request_error(req, status);
2001 * Now that we know the request was correctly signed
2002 * we have to sign the response too.
2004 req->do_signing = true;
2006 if (!NT_STATUS_IS_OK(session_status)) {
2007 return smbd_smb2_request_error(req, session_status);
2009 } else if (opcode == SMB2_OP_CANCEL) {
2010 /* Cancel requests are allowed to skip the signing */
2011 } else if (signing_required) {
2013 * If signing is required we try to sign
2014 * a possible error response
2016 req->do_signing = true;
2017 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2020 if (flags & SMB2_HDR_FLAG_CHAINED) {
2021 req->compound_related = true;
2022 req->sconn->smb2.compound_related_in_progress = true;
2025 if (call->need_session) {
2026 if (!NT_STATUS_IS_OK(session_status)) {
2027 return smbd_smb2_request_error(req, session_status);
2031 if (call->need_tcon) {
2032 SMB_ASSERT(call->need_session);
2035 * This call needs to be run as user.
2037 * smbd_smb2_request_check_tcon()
2038 * calls change_to_user() on success.
2040 status = smbd_smb2_request_check_tcon(req);
2041 if (!NT_STATUS_IS_OK(status)) {
2042 return smbd_smb2_request_error(req, status);
2044 if (req->tcon->global->encryption_required) {
2045 encryption_required = true;
2047 if (encryption_required && !req->do_encryption) {
2048 return smbd_smb2_request_error(req,
2049 NT_STATUS_ACCESS_DENIED);
2053 if (call->fileid_ofs != 0) {
2054 size_t needed = call->fileid_ofs + 16;
2055 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2056 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2057 uint64_t file_id_persistent;
2058 uint64_t file_id_volatile;
2059 struct files_struct *fsp;
2061 SMB_ASSERT(call->need_tcon);
2063 if (needed > body_size) {
2064 return smbd_smb2_request_error(req,
2065 NT_STATUS_INVALID_PARAMETER);
2068 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2069 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2071 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2072 if (fsp == NULL) {
2073 if (!call->allow_invalid_fileid) {
2074 return smbd_smb2_request_error(req,
2075 NT_STATUS_FILE_CLOSED);
2078 if (file_id_persistent != UINT64_MAX) {
2079 return smbd_smb2_request_error(req,
2080 NT_STATUS_FILE_CLOSED);
2082 if (file_id_volatile != UINT64_MAX) {
2083 return smbd_smb2_request_error(req,
2084 NT_STATUS_FILE_CLOSED);
2089 if (call->as_root) {
2090 SMB_ASSERT(call->fileid_ofs == 0);
2091 /* This call needs to be run as root */
2092 change_to_root_user();
2093 } else {
2094 SMB_ASSERT(call->need_tcon);
2097 switch (opcode) {
2098 case SMB2_OP_NEGPROT:
2100 START_PROFILE(smb2_negprot);
2101 return_value = smbd_smb2_request_process_negprot(req);
2102 END_PROFILE(smb2_negprot);
2104 break;
2106 case SMB2_OP_SESSSETUP:
2108 START_PROFILE(smb2_sesssetup);
2109 return_value = smbd_smb2_request_process_sesssetup(req);
2110 END_PROFILE(smb2_sesssetup);
2112 break;
2114 case SMB2_OP_LOGOFF:
2116 START_PROFILE(smb2_logoff);
2117 return_value = smbd_smb2_request_process_logoff(req);
2118 END_PROFILE(smb2_logoff);
2120 break;
2122 case SMB2_OP_TCON:
2124 START_PROFILE(smb2_tcon);
2125 return_value = smbd_smb2_request_process_tcon(req);
2126 END_PROFILE(smb2_tcon);
2128 break;
2130 case SMB2_OP_TDIS:
2132 START_PROFILE(smb2_tdis);
2133 return_value = smbd_smb2_request_process_tdis(req);
2134 END_PROFILE(smb2_tdis);
2136 break;
2138 case SMB2_OP_CREATE:
2140 START_PROFILE(smb2_create);
2141 return_value = smbd_smb2_request_process_create(req);
2142 END_PROFILE(smb2_create);
2144 break;
2146 case SMB2_OP_CLOSE:
2148 START_PROFILE(smb2_close);
2149 return_value = smbd_smb2_request_process_close(req);
2150 END_PROFILE(smb2_close);
2152 break;
2154 case SMB2_OP_FLUSH:
2156 START_PROFILE(smb2_flush);
2157 return_value = smbd_smb2_request_process_flush(req);
2158 END_PROFILE(smb2_flush);
2160 break;
2162 case SMB2_OP_READ:
2164 START_PROFILE(smb2_read);
2165 return_value = smbd_smb2_request_process_read(req);
2166 END_PROFILE(smb2_read);
2168 break;
2170 case SMB2_OP_WRITE:
2172 START_PROFILE(smb2_write);
2173 return_value = smbd_smb2_request_process_write(req);
2174 END_PROFILE(smb2_write);
2176 break;
2178 case SMB2_OP_LOCK:
2180 START_PROFILE(smb2_lock);
2181 return_value = smbd_smb2_request_process_lock(req);
2182 END_PROFILE(smb2_lock);
2184 break;
2186 case SMB2_OP_IOCTL:
2188 START_PROFILE(smb2_ioctl);
2189 return_value = smbd_smb2_request_process_ioctl(req);
2190 END_PROFILE(smb2_ioctl);
2192 break;
2194 case SMB2_OP_CANCEL:
2196 START_PROFILE(smb2_cancel);
2197 return_value = smbd_smb2_request_process_cancel(req);
2198 END_PROFILE(smb2_cancel);
2200 break;
2202 case SMB2_OP_KEEPALIVE:
2204 START_PROFILE(smb2_keepalive);
2205 return_value = smbd_smb2_request_process_keepalive(req);
2206 END_PROFILE(smb2_keepalive);
2208 break;
2210 case SMB2_OP_FIND:
2212 START_PROFILE(smb2_find);
2213 return_value = smbd_smb2_request_process_find(req);
2214 END_PROFILE(smb2_find);
2216 break;
2218 case SMB2_OP_NOTIFY:
2220 START_PROFILE(smb2_notify);
2221 return_value = smbd_smb2_request_process_notify(req);
2222 END_PROFILE(smb2_notify);
2224 break;
2226 case SMB2_OP_GETINFO:
2228 START_PROFILE(smb2_getinfo);
2229 return_value = smbd_smb2_request_process_getinfo(req);
2230 END_PROFILE(smb2_getinfo);
2232 break;
2234 case SMB2_OP_SETINFO:
2236 START_PROFILE(smb2_setinfo);
2237 return_value = smbd_smb2_request_process_setinfo(req);
2238 END_PROFILE(smb2_setinfo);
2240 break;
2242 case SMB2_OP_BREAK:
2244 START_PROFILE(smb2_break);
2245 return_value = smbd_smb2_request_process_break(req);
2246 END_PROFILE(smb2_break);
2248 break;
2250 default:
2251 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2252 break;
2254 return return_value;
2257 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2259 struct smbXsrv_connection *conn = req->sconn->conn;
2260 struct tevent_req *subreq;
2261 int first_idx = 1;
2262 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2263 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2264 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2266 req->subreq = NULL;
2267 TALLOC_FREE(req->async_te);
2269 if (req->do_encryption &&
2270 (firsttf->iov_len == 0) &&
2271 (req->first_key.length == 0) &&
2272 (req->session != NULL) &&
2273 (req->session->global->encryption_key.length != 0))
2275 DATA_BLOB encryption_key = req->session->global->encryption_key;
2276 uint8_t *tf;
2277 uint64_t session_id = req->session->global->session_wire_id;
2278 struct smbXsrv_session *x = req->session;
2279 uint64_t nonce_high;
2280 uint64_t nonce_low;
2282 nonce_high = x->nonce_high;
2283 nonce_low = x->nonce_low;
2285 x->nonce_low += 1;
2286 if (x->nonce_low == 0) {
2287 x->nonce_low += 1;
2288 x->nonce_high += 1;
2292 * We need to place the SMB2_TRANSFORM header before the
2293 * first SMB2 header
2297 * we need to remember the encryption key
2298 * and defer the signing/encryption until
2299 * we are sure that we do not change
2300 * the header again.
2302 req->first_key = data_blob_dup_talloc(req, encryption_key);
2303 if (req->first_key.data == NULL) {
2304 return NT_STATUS_NO_MEMORY;
2307 tf = talloc_zero_array(req->out.vector, uint8_t,
2308 SMB2_TF_HDR_SIZE);
2309 if (tf == NULL) {
2310 return NT_STATUS_NO_MEMORY;
2313 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2314 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2315 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2316 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2318 firsttf->iov_base = (void *)tf;
2319 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2322 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2323 (req->last_key.length > 0) &&
2324 (firsttf->iov_len == 0))
2326 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2327 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2328 NTSTATUS status;
2331 * As we are sure the header of the last request in the
2332 * compound chain will not change, we can to sign here
2333 * with the last signing key we remembered.
2335 status = smb2_signing_sign_pdu(req->last_key,
2336 conn->protocol,
2337 lasthdr,
2338 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2339 if (!NT_STATUS_IS_OK(status)) {
2340 return status;
2343 data_blob_clear_free(&req->last_key);
2345 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2347 if (req->current_idx < req->out.vector_count) {
2349 * We must process the remaining compound
2350 * SMB2 requests before any new incoming SMB2
2351 * requests. This is because incoming SMB2
2352 * requests may include a cancel for a
2353 * compound request we haven't processed
2354 * yet.
2356 struct tevent_immediate *im = tevent_create_immediate(req);
2357 if (!im) {
2358 return NT_STATUS_NO_MEMORY;
2361 if (req->do_signing && firsttf->iov_len == 0) {
2362 struct smbXsrv_session *x = req->session;
2363 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2366 * we need to remember the signing key
2367 * and defer the signing until
2368 * we are sure that we do not change
2369 * the header again.
2371 req->last_key = data_blob_dup_talloc(req, signing_key);
2372 if (req->last_key.data == NULL) {
2373 return NT_STATUS_NO_MEMORY;
2377 tevent_schedule_immediate(im,
2378 req->sconn->ev_ctx,
2379 smbd_smb2_request_dispatch_immediate,
2380 req);
2381 return NT_STATUS_OK;
2384 if (req->compound_related) {
2385 req->compound_related = false;
2386 req->sconn->smb2.compound_related_in_progress = false;
2389 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2391 /* Set credit for these operations (zero credits if this
2392 is a final reply for an async operation). */
2393 smb2_calculate_credits(req, req);
2396 * now check if we need to sign the current response
2398 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2399 NTSTATUS status;
2401 status = smb2_signing_encrypt_pdu(req->first_key,
2402 conn->protocol,
2403 firsttf,
2404 req->out.vector_count - first_idx);
2405 if (!NT_STATUS_IS_OK(status)) {
2406 return status;
2408 } else if (req->do_signing) {
2409 NTSTATUS status;
2410 struct smbXsrv_session *x = req->session;
2411 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2413 status = smb2_signing_sign_pdu(signing_key,
2414 conn->protocol,
2415 outhdr,
2416 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2417 if (!NT_STATUS_IS_OK(status)) {
2418 return status;
2421 data_blob_clear_free(&req->first_key);
2423 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2424 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2425 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2426 /* Dynamic part is NULL. Chop it off,
2427 We're going to send it via sendfile. */
2428 req->out.vector_count -= 1;
2431 subreq = tstream_writev_queue_send(req,
2432 req->sconn->ev_ctx,
2433 req->sconn->smb2.stream,
2434 req->sconn->smb2.send_queue,
2435 req->out.vector,
2436 req->out.vector_count);
2437 if (subreq == NULL) {
2438 return NT_STATUS_NO_MEMORY;
2440 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2442 * We're done with this request -
2443 * move it off the "being processed" queue.
2445 DLIST_REMOVE(req->sconn->smb2.requests, req);
2447 return NT_STATUS_OK;
2450 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2452 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2453 struct tevent_immediate *im,
2454 void *private_data)
2456 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2457 struct smbd_smb2_request);
2458 struct smbd_server_connection *sconn = req->sconn;
2459 NTSTATUS status;
2461 TALLOC_FREE(im);
2463 if (DEBUGLEVEL >= 10) {
2464 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2465 req->current_idx, req->in.vector_count));
2466 print_req_vectors(req);
2469 status = smbd_smb2_request_dispatch(req);
2470 if (!NT_STATUS_IS_OK(status)) {
2471 smbd_server_connection_terminate(sconn, nt_errstr(status));
2472 return;
2475 status = smbd_smb2_request_next_incoming(sconn);
2476 if (!NT_STATUS_IS_OK(status)) {
2477 smbd_server_connection_terminate(sconn, nt_errstr(status));
2478 return;
2482 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2484 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2485 struct smbd_smb2_request);
2486 struct smbd_server_connection *sconn = req->sconn;
2487 int ret;
2488 int sys_errno;
2489 NTSTATUS status;
2491 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2492 TALLOC_FREE(subreq);
2493 TALLOC_FREE(req);
2494 if (ret == -1) {
2495 status = map_nt_error_from_unix(sys_errno);
2496 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2497 nt_errstr(status)));
2498 smbd_server_connection_terminate(sconn, nt_errstr(status));
2499 return;
2502 status = smbd_smb2_request_next_incoming(sconn);
2503 if (!NT_STATUS_IS_OK(status)) {
2504 smbd_server_connection_terminate(sconn, nt_errstr(status));
2505 return;
2509 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2510 NTSTATUS status,
2511 DATA_BLOB body, DATA_BLOB *dyn,
2512 const char *location)
2514 uint8_t *outhdr;
2515 struct iovec *outbody_v;
2516 struct iovec *outdyn_v;
2517 uint32_t next_command_ofs;
2519 DEBUG(10,("smbd_smb2_request_done_ex: "
2520 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2521 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2522 dyn ? "yes": "no",
2523 (unsigned int)(dyn ? dyn->length : 0),
2524 location));
2526 if (body.length < 2) {
2527 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2530 if ((body.length % 2) != 0) {
2531 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2534 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2535 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2536 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2538 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2539 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2541 outbody_v->iov_base = (void *)body.data;
2542 outbody_v->iov_len = body.length;
2544 if (dyn) {
2545 outdyn_v->iov_base = (void *)dyn->data;
2546 outdyn_v->iov_len = dyn->length;
2547 } else {
2548 outdyn_v->iov_base = NULL;
2549 outdyn_v->iov_len = 0;
2552 /* see if we need to recalculate the offset to the next response */
2553 if (next_command_ofs > 0) {
2554 next_command_ofs = SMB2_HDR_BODY;
2555 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2556 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2559 if ((next_command_ofs % 8) != 0) {
2560 size_t pad_size = 8 - (next_command_ofs % 8);
2561 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2563 * if the dyn buffer is empty
2564 * we can use it to add padding
2566 uint8_t *pad;
2568 pad = talloc_zero_array(req->out.vector,
2569 uint8_t, pad_size);
2570 if (pad == NULL) {
2571 return smbd_smb2_request_error(req,
2572 NT_STATUS_NO_MEMORY);
2575 outdyn_v->iov_base = (void *)pad;
2576 outdyn_v->iov_len = pad_size;
2577 } else {
2579 * For now we copy the dynamic buffer
2580 * and add the padding to the new buffer
2582 size_t old_size;
2583 uint8_t *old_dyn;
2584 size_t new_size;
2585 uint8_t *new_dyn;
2587 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2588 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2590 new_size = old_size + pad_size;
2591 new_dyn = talloc_zero_array(req->out.vector,
2592 uint8_t, new_size);
2593 if (new_dyn == NULL) {
2594 return smbd_smb2_request_error(req,
2595 NT_STATUS_NO_MEMORY);
2598 memcpy(new_dyn, old_dyn, old_size);
2599 memset(new_dyn + old_size, 0, pad_size);
2601 outdyn_v->iov_base = (void *)new_dyn;
2602 outdyn_v->iov_len = new_size;
2604 next_command_ofs += pad_size;
2607 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2609 return smbd_smb2_request_reply(req);
2612 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2613 NTSTATUS status,
2614 DATA_BLOB *info,
2615 const char *location)
2617 DATA_BLOB body;
2618 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2620 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2621 req->current_idx, nt_errstr(status), info ? " +info" : "",
2622 location));
2624 body.data = outhdr + SMB2_HDR_BODY;
2625 body.length = 8;
2626 SSVAL(body.data, 0, 9);
2628 if (info) {
2629 SIVAL(body.data, 0x04, info->length);
2630 } else {
2631 /* Allocated size of req->out.vector[i].iov_base
2632 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2633 * 1 byte without having to do an alloc.
2635 info = talloc_zero_array(req->out.vector,
2636 DATA_BLOB,
2638 if (!info) {
2639 return NT_STATUS_NO_MEMORY;
2641 info->data = ((uint8_t *)outhdr) +
2642 OUTVEC_ALLOC_SIZE - 1;
2643 info->length = 1;
2644 SCVAL(info->data, 0, 0);
2648 * Note: Even if there is an error, continue to process the request.
2649 * per MS-SMB2.
2652 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2656 struct smbd_smb2_send_oplock_break_state {
2657 struct smbd_server_connection *sconn;
2658 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18];
2659 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2662 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2664 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2665 struct smbXsrv_session *session,
2666 struct smbXsrv_tcon *tcon,
2667 struct smbXsrv_open *op,
2668 uint8_t oplock_level)
2670 struct smbd_smb2_send_oplock_break_state *state;
2671 struct smbXsrv_connection *conn = sconn->conn;
2672 struct tevent_req *subreq;
2673 uint8_t *tf;
2674 size_t tf_len;
2675 uint8_t *hdr;
2676 uint8_t *body;
2677 size_t body_len;
2678 uint8_t *dyn;
2679 size_t dyn_len;
2680 bool do_encryption = session->global->encryption_required;
2681 uint64_t nonce_high = 0;
2682 uint64_t nonce_low = 0;
2684 if (tcon->global->encryption_required) {
2685 do_encryption = true;
2688 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2689 if (state == NULL) {
2690 return NT_STATUS_NO_MEMORY;
2692 state->sconn = sconn;
2694 tf = state->buf + NBT_HDR_SIZE;
2695 tf_len = SMB2_TF_HDR_SIZE;
2696 hdr = tf + tf_len;
2697 body = hdr + SMB2_HDR_BODY;
2698 body_len = 0x18;
2699 dyn = body + body_len;
2700 dyn_len = 0;
2702 if (do_encryption) {
2703 nonce_high = session->nonce_high;
2704 nonce_low = session->nonce_low;
2706 session->nonce_low += 1;
2707 if (session->nonce_low == 0) {
2708 session->nonce_low += 1;
2709 session->nonce_high += 1;
2713 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2714 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2715 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2716 SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
2718 SIVAL(hdr, 0, SMB2_MAGIC);
2719 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2720 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2721 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2722 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2723 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2724 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2725 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2726 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2727 SIVAL(hdr, SMB2_HDR_PID, 0);
2728 SIVAL(hdr, SMB2_HDR_TID, 0);
2729 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2730 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2732 SSVAL(body, 0x00, body_len);
2734 SCVAL(body, 0x02, oplock_level);
2735 SCVAL(body, 0x03, 0); /* reserved */
2736 SIVAL(body, 0x04, 0); /* reserved */
2737 SBVAL(body, 0x08, op->global->open_persistent_id);
2738 SBVAL(body, 0x10, op->global->open_volatile_id);
2740 state->vector[0].iov_base = (void *)state->buf;
2741 state->vector[0].iov_len = NBT_HDR_SIZE;
2743 if (do_encryption) {
2744 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
2745 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
2746 } else {
2747 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
2748 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
2751 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
2752 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
2754 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
2755 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = body_len;
2757 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
2758 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_len;
2760 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2762 if (do_encryption) {
2763 NTSTATUS status;
2764 DATA_BLOB encryption_key = session->global->encryption_key;
2766 status = smb2_signing_encrypt_pdu(encryption_key,
2767 conn->protocol,
2768 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2769 SMBD_SMB2_NUM_IOV_PER_REQ);
2770 if (!NT_STATUS_IS_OK(status)) {
2771 return status;
2775 subreq = tstream_writev_queue_send(state,
2776 sconn->ev_ctx,
2777 sconn->smb2.stream,
2778 sconn->smb2.send_queue,
2779 state->vector,
2780 ARRAY_SIZE(state->vector));
2781 if (subreq == NULL) {
2782 return NT_STATUS_NO_MEMORY;
2784 tevent_req_set_callback(subreq,
2785 smbd_smb2_oplock_break_writev_done,
2786 state);
2788 return NT_STATUS_OK;
2791 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2793 struct smbd_smb2_send_oplock_break_state *state =
2794 tevent_req_callback_data(subreq,
2795 struct smbd_smb2_send_oplock_break_state);
2796 struct smbd_server_connection *sconn = state->sconn;
2797 int ret;
2798 int sys_errno;
2800 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2801 TALLOC_FREE(subreq);
2802 if (ret == -1) {
2803 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2804 smbd_server_connection_terminate(sconn, nt_errstr(status));
2805 return;
2808 TALLOC_FREE(state);
2811 struct smbd_smb2_request_read_state {
2812 struct tevent_context *ev;
2813 struct smbd_server_connection *sconn;
2814 struct smbd_smb2_request *smb2_req;
2815 struct {
2816 uint8_t nbt[NBT_HDR_SIZE];
2817 bool done;
2818 } hdr;
2819 size_t pktlen;
2820 uint8_t *pktbuf;
2823 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2824 void *private_data,
2825 TALLOC_CTX *mem_ctx,
2826 struct iovec **_vector,
2827 size_t *_count);
2828 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2830 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2831 struct tevent_context *ev,
2832 struct smbd_server_connection *sconn)
2834 struct tevent_req *req;
2835 struct smbd_smb2_request_read_state *state;
2836 struct tevent_req *subreq;
2838 req = tevent_req_create(mem_ctx, &state,
2839 struct smbd_smb2_request_read_state);
2840 if (req == NULL) {
2841 return NULL;
2843 state->ev = ev;
2844 state->sconn = sconn;
2846 state->smb2_req = smbd_smb2_request_allocate(state);
2847 if (tevent_req_nomem(state->smb2_req, req)) {
2848 return tevent_req_post(req, ev);
2850 state->smb2_req->sconn = sconn;
2852 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2853 state->ev,
2854 state->sconn->smb2.stream,
2855 state->sconn->smb2.recv_queue,
2856 smbd_smb2_request_next_vector,
2857 state);
2858 if (tevent_req_nomem(subreq, req)) {
2859 return tevent_req_post(req, ev);
2861 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2863 return req;
2866 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2867 void *private_data,
2868 TALLOC_CTX *mem_ctx,
2869 struct iovec **_vector,
2870 size_t *_count)
2872 struct smbd_smb2_request_read_state *state =
2873 talloc_get_type_abort(private_data,
2874 struct smbd_smb2_request_read_state);
2875 struct iovec *vector;
2877 if (state->pktlen > 0) {
2878 /* if there're no remaining bytes, we're done */
2879 *_vector = NULL;
2880 *_count = 0;
2881 return 0;
2884 if (!state->hdr.done) {
2886 * first we need to get the NBT header
2888 vector = talloc_array(mem_ctx, struct iovec, 1);
2889 if (vector == NULL) {
2890 return -1;
2893 vector[0].iov_base = (void *)state->hdr.nbt;
2894 vector[0].iov_len = NBT_HDR_SIZE;
2896 *_vector = vector;
2897 *_count = 1;
2899 state->hdr.done = true;
2900 return 0;
2904 * Now we analyze the NBT header
2906 state->pktlen = smb2_len(state->hdr.nbt);
2908 if (state->pktlen == 0) {
2909 /* if there're no remaining bytes, we're done */
2910 *_vector = NULL;
2911 *_count = 0;
2912 return 0;
2915 state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
2916 if (state->pktbuf == NULL) {
2917 return -1;
2920 vector = talloc_array(mem_ctx, struct iovec, 1);
2921 if (vector == NULL) {
2922 return -1;
2925 vector[0].iov_base = (void *)state->pktbuf;
2926 vector[0].iov_len = state->pktlen;
2928 *_vector = vector;
2929 *_count = 1;
2930 return 0;
2933 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2935 struct tevent_req *req =
2936 tevent_req_callback_data(subreq,
2937 struct tevent_req);
2938 struct smbd_smb2_request_read_state *state =
2939 tevent_req_data(req,
2940 struct smbd_smb2_request_read_state);
2941 int ret;
2942 int sys_errno;
2943 NTSTATUS status;
2944 NTTIME now;
2946 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2947 TALLOC_FREE(subreq);
2948 if (ret == -1) {
2949 status = map_nt_error_from_unix(sys_errno);
2950 tevent_req_nterror(req, status);
2951 return;
2954 if (state->hdr.nbt[0] != 0x00) {
2955 DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
2956 state->hdr.nbt[0]));
2958 ZERO_STRUCT(state->hdr);
2959 TALLOC_FREE(state->pktbuf);
2960 state->pktlen = 0;
2962 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2963 state->ev,
2964 state->sconn->smb2.stream,
2965 state->sconn->smb2.recv_queue,
2966 smbd_smb2_request_next_vector,
2967 state);
2968 if (tevent_req_nomem(subreq, req)) {
2969 return;
2971 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2972 return;
2975 state->smb2_req->request_time = timeval_current();
2976 now = timeval_to_nttime(&state->smb2_req->request_time);
2978 status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
2979 now,
2980 state->pktbuf,
2981 state->pktlen,
2982 state->smb2_req,
2983 &state->smb2_req->in.vector,
2984 &state->smb2_req->in.vector_count);
2985 if (tevent_req_nterror(req, status)) {
2986 return;
2989 state->smb2_req->current_idx = 1;
2991 tevent_req_done(req);
2994 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2995 TALLOC_CTX *mem_ctx,
2996 struct smbd_smb2_request **_smb2_req)
2998 struct smbd_smb2_request_read_state *state =
2999 tevent_req_data(req,
3000 struct smbd_smb2_request_read_state);
3001 NTSTATUS status;
3003 if (tevent_req_is_nterror(req, &status)) {
3004 tevent_req_received(req);
3005 return status;
3008 *_smb2_req = talloc_move(mem_ctx, &state->smb2_req);
3009 tevent_req_received(req);
3010 return NT_STATUS_OK;
3013 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
3015 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
3017 size_t max_send_queue_len;
3018 size_t cur_send_queue_len;
3019 struct tevent_req *subreq;
3021 if (sconn->smb2.compound_related_in_progress) {
3023 * Can't read another until the related
3024 * compound is done.
3026 return NT_STATUS_OK;
3029 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
3031 * if there is already a smbd_smb2_request_read
3032 * pending, we are done.
3034 return NT_STATUS_OK;
3037 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
3038 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
3040 if (cur_send_queue_len > max_send_queue_len) {
3042 * if we have a lot of requests to send,
3043 * we wait until they are on the wire until we
3044 * ask for the next request.
3046 return NT_STATUS_OK;
3049 /* ask for the next request */
3050 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
3051 if (subreq == NULL) {
3052 return NT_STATUS_NO_MEMORY;
3054 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
3056 return NT_STATUS_OK;
3059 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
3060 uint8_t *inbuf, size_t size)
3062 NTSTATUS status;
3063 struct smbd_smb2_request *req = NULL;
3065 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
3066 (unsigned int)size));
3068 status = smbd_initialize_smb2(sconn);
3069 if (!NT_STATUS_IS_OK(status)) {
3070 smbd_server_connection_terminate(sconn, nt_errstr(status));
3071 return;
3074 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
3075 if (!NT_STATUS_IS_OK(status)) {
3076 smbd_server_connection_terminate(sconn, nt_errstr(status));
3077 return;
3080 status = smbd_smb2_request_validate(req);
3081 if (!NT_STATUS_IS_OK(status)) {
3082 smbd_server_connection_terminate(sconn, nt_errstr(status));
3083 return;
3086 status = smbd_smb2_request_setup_out(req);
3087 if (!NT_STATUS_IS_OK(status)) {
3088 smbd_server_connection_terminate(sconn, nt_errstr(status));
3089 return;
3092 status = smbd_smb2_request_dispatch(req);
3093 if (!NT_STATUS_IS_OK(status)) {
3094 smbd_server_connection_terminate(sconn, nt_errstr(status));
3095 return;
3098 status = smbd_smb2_request_next_incoming(sconn);
3099 if (!NT_STATUS_IS_OK(status)) {
3100 smbd_server_connection_terminate(sconn, nt_errstr(status));
3101 return;
3104 sconn->num_requests++;
3107 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
3109 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
3110 struct smbd_server_connection);
3111 NTSTATUS status;
3112 struct smbd_smb2_request *req = NULL;
3114 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
3115 TALLOC_FREE(subreq);
3116 if (!NT_STATUS_IS_OK(status)) {
3117 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
3118 nt_errstr(status)));
3119 smbd_server_connection_terminate(sconn, nt_errstr(status));
3120 return;
3123 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
3124 req->current_idx, req->in.vector_count));
3126 status = smbd_smb2_request_validate(req);
3127 if (!NT_STATUS_IS_OK(status)) {
3128 smbd_server_connection_terminate(sconn, nt_errstr(status));
3129 return;
3132 status = smbd_smb2_request_setup_out(req);
3133 if (!NT_STATUS_IS_OK(status)) {
3134 smbd_server_connection_terminate(sconn, nt_errstr(status));
3135 return;
3138 status = smbd_smb2_request_dispatch(req);
3139 if (!NT_STATUS_IS_OK(status)) {
3140 smbd_server_connection_terminate(sconn, nt_errstr(status));
3141 return;
3144 status = smbd_smb2_request_next_incoming(sconn);
3145 if (!NT_STATUS_IS_OK(status)) {
3146 smbd_server_connection_terminate(sconn, nt_errstr(status));
3147 return;
3150 sconn->num_requests++;
3152 /* The timeout_processing function isn't run nearly
3153 often enough to implement 'max log size' without
3154 overrunning the size of the file by many megabytes.
3155 This is especially true if we are running at debug
3156 level 10. Checking every 50 SMB2s is a nice
3157 tradeoff of performance vs log file size overrun. */
3159 if ((sconn->num_requests % 50) == 0 &&
3160 need_to_check_log_size()) {
3161 change_to_root_user();
3162 check_log_size();