s3:smbd:smb2: simplify smbd_smb2_request_validate() and smbd_smb2_request_dispatch()
[Samba/gebeck_regimport.git] / source3 / smbd / smb2_server.c
blob77f25a9a82139c771ba2bf45d7430502d769914b
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 tevent_req_cancel(req->subreq);
1301 return smbd_smb2_request_error(req,
1302 NT_STATUS_INSUFFICIENT_RESOURCES);
1305 if (DEBUGLEVEL >= 10) {
1306 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1307 (unsigned int)req->current_idx );
1308 print_req_vectors(req);
1311 if (req->out.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ)) {
1313 * This is a compound reply. We
1314 * must do an interim response
1315 * followed by the async response
1316 * to match W2K8R2.
1318 status = smb2_send_async_interim_response(req);
1319 if (!NT_STATUS_IS_OK(status)) {
1320 return status;
1322 data_blob_clear_free(&req->first_key);
1325 * We're splitting off the last SMB2
1326 * request in a compound set, and the
1327 * smb2_send_async_interim_response()
1328 * call above just sent all the replies
1329 * for the previous SMB2 requests in
1330 * this compound set. So we're no longer
1331 * in the "compound_related_in_progress"
1332 * state, and this is no longer a compound
1333 * request.
1335 req->compound_related = false;
1336 req->sconn->smb2.compound_related_in_progress = false;
1338 req->current_idx = 1;
1340 /* Re-arrange the in.vectors. */
1341 memmove(&req->in.vector[req->current_idx],
1342 &req->in.vector[idx],
1343 sizeof(req->in.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1344 req->in.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1346 /* Re-arrange the out.vectors. */
1347 memmove(&req->out.vector[req->current_idx],
1348 &req->out.vector[idx],
1349 sizeof(req->out.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
1350 req->out.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
1352 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1353 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1354 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1356 data_blob_clear_free(&req->last_key);
1358 defer_endtime = timeval_current_ofs_usec(defer_time);
1359 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1360 req, defer_endtime,
1361 smbd_smb2_request_pending_timer,
1362 req);
1363 if (req->async_te == NULL) {
1364 return NT_STATUS_NO_MEMORY;
1367 return NT_STATUS_OK;
1370 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1371 struct tevent_timer *te,
1372 struct timeval current_time,
1373 void *private_data)
1375 struct smbd_smb2_request *req =
1376 talloc_get_type_abort(private_data,
1377 struct smbd_smb2_request);
1378 struct smbd_smb2_request_pending_state *state = NULL;
1379 uint8_t *outhdr = NULL;
1380 const uint8_t *inhdr = NULL;
1381 uint8_t *tf = NULL;
1382 size_t tf_len = 0;
1383 uint8_t *hdr = NULL;
1384 uint8_t *body = NULL;
1385 uint8_t *dyn = NULL;
1386 uint32_t flags = 0;
1387 uint64_t session_id = 0;
1388 uint64_t message_id = 0;
1389 uint64_t nonce_high = 0;
1390 uint64_t nonce_low = 0;
1391 uint64_t async_id = 0;
1392 struct tevent_req *subreq = NULL;
1394 TALLOC_FREE(req->async_te);
1396 /* Ensure our final reply matches the interim one. */
1397 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1398 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1399 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1400 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1401 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1403 async_id = message_id; /* keep it simple for now... */
1405 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1406 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1408 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1409 "going async\n",
1410 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1411 (unsigned long long)async_id ));
1414 * What we send is identical to a smbd_smb2_request_error
1415 * packet with an error status of STATUS_PENDING. Make use
1416 * of this fact sometime when refactoring. JRA.
1419 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1420 if (state == NULL) {
1421 smbd_server_connection_terminate(req->sconn,
1422 nt_errstr(NT_STATUS_NO_MEMORY));
1423 return;
1425 state->sconn = req->sconn;
1427 tf = state->buf + NBT_HDR_SIZE;
1428 tf_len = SMB2_TF_HDR_SIZE;
1430 hdr = tf + SMB2_TF_HDR_SIZE;
1431 body = hdr + SMB2_HDR_BODY;
1432 dyn = body + 8;
1434 if (req->do_encryption) {
1435 struct smbXsrv_session *x = req->session;
1437 nonce_high = x->nonce_high;
1438 nonce_low = x->nonce_low;
1440 x->nonce_low += 1;
1441 if (x->nonce_low == 0) {
1442 x->nonce_low += 1;
1443 x->nonce_high += 1;
1447 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1448 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1449 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1450 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1452 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1453 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1454 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1455 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1456 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1458 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1459 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1460 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1461 SBVAL(hdr, SMB2_HDR_PID, async_id);
1462 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1463 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1464 memcpy(hdr+SMB2_HDR_SIGNATURE,
1465 outhdr+SMB2_HDR_SIGNATURE, 16);
1467 SSVAL(body, 0x00, 0x08 + 1);
1469 SCVAL(body, 0x02, 0);
1470 SCVAL(body, 0x03, 0);
1471 SIVAL(body, 0x04, 0);
1472 /* Match W2K8R2... */
1473 SCVAL(dyn, 0x00, 0x21);
1475 state->vector[0].iov_base = (void *)state->buf;
1476 state->vector[0].iov_len = NBT_HDR_SIZE;
1478 if (req->do_encryption) {
1479 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1480 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1481 } else {
1482 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1483 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1486 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1487 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1489 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1490 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1492 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1493 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1495 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1497 /* Ensure we correctly go through crediting. Grant
1498 the credits now, and zero credits on the final
1499 response. */
1500 smb2_set_operation_credit(req->sconn,
1501 SMBD_SMB2_IN_HDR_IOV(req),
1502 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1504 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1506 if (DEBUGLVL(10)) {
1507 int i;
1509 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1510 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1511 (unsigned int)i,
1512 (unsigned int)ARRAY_SIZE(state->vector),
1513 (unsigned int)state->vector[i].iov_len);
1517 if (req->do_encryption) {
1518 NTSTATUS status;
1519 struct smbXsrv_session *x = req->session;
1520 struct smbXsrv_connection *conn = x->connection;
1521 DATA_BLOB encryption_key = x->global->encryption_key;
1523 status = smb2_signing_encrypt_pdu(encryption_key,
1524 conn->protocol,
1525 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1526 SMBD_SMB2_NUM_IOV_PER_REQ);
1527 if (!NT_STATUS_IS_OK(status)) {
1528 smbd_server_connection_terminate(req->sconn,
1529 nt_errstr(status));
1530 return;
1532 } else if (req->do_signing) {
1533 NTSTATUS status;
1534 struct smbXsrv_session *x = req->session;
1535 struct smbXsrv_connection *conn = x->connection;
1536 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1538 status = smb2_signing_sign_pdu(signing_key,
1539 conn->protocol,
1540 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1541 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1542 if (!NT_STATUS_IS_OK(status)) {
1543 smbd_server_connection_terminate(req->sconn,
1544 nt_errstr(status));
1545 return;
1549 subreq = tstream_writev_queue_send(state,
1550 state->sconn->ev_ctx,
1551 state->sconn->smb2.stream,
1552 state->sconn->smb2.send_queue,
1553 state->vector,
1554 ARRAY_SIZE(state->vector));
1555 if (subreq == NULL) {
1556 smbd_server_connection_terminate(state->sconn,
1557 nt_errstr(NT_STATUS_NO_MEMORY));
1558 return;
1560 tevent_req_set_callback(subreq,
1561 smbd_smb2_request_pending_writev_done,
1562 state);
1565 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1567 struct smbd_server_connection *sconn = req->sconn;
1568 struct smbd_smb2_request *cur;
1569 const uint8_t *inhdr;
1570 uint32_t flags;
1571 uint64_t search_message_id;
1572 uint64_t search_async_id;
1573 uint64_t found_id;
1575 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1577 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1578 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1579 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1582 * we don't need the request anymore
1583 * cancel requests never have a response
1585 DLIST_REMOVE(req->sconn->smb2.requests, req);
1586 TALLOC_FREE(req);
1588 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1589 const uint8_t *outhdr;
1590 uint64_t message_id;
1591 uint64_t async_id;
1593 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1595 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1596 async_id = BVAL(outhdr, SMB2_HDR_PID);
1598 if (flags & SMB2_HDR_FLAG_ASYNC) {
1599 if (search_async_id == async_id) {
1600 found_id = async_id;
1601 break;
1603 } else {
1604 if (search_message_id == message_id) {
1605 found_id = message_id;
1606 break;
1611 if (cur && cur->subreq) {
1612 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1613 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1614 "cancel opcode[%s] mid %llu\n",
1615 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
1616 (unsigned long long)found_id ));
1617 tevent_req_cancel(cur->subreq);
1620 return NT_STATUS_OK;
1623 /*************************************************************
1624 Ensure an incoming tid is a valid one for us to access.
1625 Change to the associated uid credentials and chdir to the
1626 valid tid directory.
1627 *************************************************************/
1629 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1631 const uint8_t *inhdr;
1632 uint32_t in_flags;
1633 uint32_t in_tid;
1634 struct smbXsrv_tcon *tcon;
1635 NTSTATUS status;
1636 NTTIME now = timeval_to_nttime(&req->request_time);
1638 req->tcon = NULL;
1640 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1642 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1643 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1645 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1646 in_tid = req->last_tid;
1649 req->last_tid = 0;
1651 status = smb2srv_tcon_lookup(req->session,
1652 in_tid, now, &tcon);
1653 if (!NT_STATUS_IS_OK(status)) {
1654 return status;
1657 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1658 return NT_STATUS_ACCESS_DENIED;
1661 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1662 if (!set_current_service(tcon->compat, 0, true)) {
1663 return NT_STATUS_ACCESS_DENIED;
1666 req->tcon = tcon;
1667 req->last_tid = in_tid;
1669 return NT_STATUS_OK;
1672 /*************************************************************
1673 Ensure an incoming session_id is a valid one for us to access.
1674 *************************************************************/
1676 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1678 const uint8_t *inhdr;
1679 uint32_t in_flags;
1680 uint16_t in_opcode;
1681 uint64_t in_session_id;
1682 struct smbXsrv_session *session = NULL;
1683 struct auth_session_info *session_info;
1684 NTSTATUS status;
1685 NTTIME now = timeval_to_nttime(&req->request_time);
1687 req->session = NULL;
1688 req->tcon = NULL;
1690 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1692 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1693 in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1694 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1696 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1697 in_session_id = req->last_session_id;
1700 req->last_session_id = 0;
1702 /* lookup an existing session */
1703 status = smb2srv_session_lookup(req->sconn->conn,
1704 in_session_id, now,
1705 &session);
1706 if (session) {
1707 req->session = session;
1708 req->last_session_id = in_session_id;
1710 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1711 switch (in_opcode) {
1712 case SMB2_OP_SESSSETUP:
1713 status = NT_STATUS_OK;
1714 break;
1715 default:
1716 break;
1719 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1720 switch (in_opcode) {
1721 case SMB2_OP_TCON:
1722 case SMB2_OP_CREATE:
1723 case SMB2_OP_GETINFO:
1724 case SMB2_OP_SETINFO:
1725 return NT_STATUS_INVALID_HANDLE;
1726 default:
1728 * Notice the check for
1729 * (session_info == NULL)
1730 * below.
1732 status = NT_STATUS_OK;
1733 break;
1736 if (!NT_STATUS_IS_OK(status)) {
1737 return status;
1740 session_info = session->global->auth_session_info;
1741 if (session_info == NULL) {
1742 return NT_STATUS_INVALID_HANDLE;
1745 set_current_user_info(session_info->unix_info->sanitized_username,
1746 session_info->unix_info->unix_name,
1747 session_info->info->domain_name);
1749 return NT_STATUS_OK;
1752 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1753 uint32_t data_length)
1755 uint16_t needed_charge;
1756 uint16_t credit_charge = 1;
1757 const uint8_t *inhdr;
1759 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1761 if (req->sconn->smb2.supports_multicredit) {
1762 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1763 credit_charge = MAX(credit_charge, 1);
1766 needed_charge = (data_length - 1)/ 65536 + 1;
1768 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1769 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1770 credit_charge, needed_charge));
1772 if (needed_charge > credit_charge) {
1773 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1774 credit_charge, needed_charge));
1775 return NT_STATUS_INVALID_PARAMETER;
1778 return NT_STATUS_OK;
1781 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1782 size_t expected_body_size)
1784 struct iovec *inhdr_v;
1785 const uint8_t *inhdr;
1786 uint16_t opcode;
1787 const uint8_t *inbody;
1788 size_t body_size;
1789 size_t min_dyn_size = expected_body_size & 0x00000001;
1790 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1793 * The following should be checked already.
1795 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1796 return NT_STATUS_INTERNAL_ERROR;
1798 if (req->current_idx > max_idx) {
1799 return NT_STATUS_INTERNAL_ERROR;
1802 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1803 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1804 return NT_STATUS_INTERNAL_ERROR;
1806 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1807 return NT_STATUS_INTERNAL_ERROR;
1810 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1811 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1813 switch (opcode) {
1814 case SMB2_OP_IOCTL:
1815 case SMB2_OP_GETINFO:
1816 min_dyn_size = 0;
1817 break;
1821 * Now check the expected body size,
1822 * where the last byte might be in the
1823 * dynamic section..
1825 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1826 return NT_STATUS_INVALID_PARAMETER;
1828 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1829 return NT_STATUS_INVALID_PARAMETER;
1832 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1834 body_size = SVAL(inbody, 0x00);
1835 if (body_size != expected_body_size) {
1836 return NT_STATUS_INVALID_PARAMETER;
1839 return NT_STATUS_OK;
1842 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1844 struct smbXsrv_connection *conn = req->sconn->conn;
1845 const struct smbd_smb2_dispatch_table *call = NULL;
1846 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1847 const uint8_t *inhdr;
1848 uint16_t opcode;
1849 uint32_t flags;
1850 uint64_t mid;
1851 NTSTATUS status;
1852 NTSTATUS session_status;
1853 uint32_t allowed_flags;
1854 NTSTATUS return_value;
1855 struct smbXsrv_session *x = NULL;
1856 bool signing_required = false;
1857 bool encryption_required = false;
1859 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1861 /* TODO: verify more things */
1863 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1864 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
1865 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1866 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1867 smb2_opcode_name(opcode),
1868 (unsigned long long)mid));
1870 if (conn->protocol >= PROTOCOL_SMB2_02) {
1872 * once the protocol is negotiated
1873 * SMB2_OP_NEGPROT is not allowed anymore
1875 if (opcode == SMB2_OP_NEGPROT) {
1876 /* drop the connection */
1877 return NT_STATUS_INVALID_PARAMETER;
1879 } else {
1881 * if the protocol is not negotiated yet
1882 * only SMB2_OP_NEGPROT is allowed.
1884 if (opcode != SMB2_OP_NEGPROT) {
1885 /* drop the connection */
1886 return NT_STATUS_INVALID_PARAMETER;
1891 * Check if the client provided a valid session id,
1892 * if so smbd_smb2_request_check_session() calls
1893 * set_current_user_info().
1895 * As some command don't require a valid session id
1896 * we defer the check of the session_status
1898 session_status = smbd_smb2_request_check_session(req);
1899 x = req->session;
1900 if (x != NULL) {
1901 signing_required = x->global->signing_required;
1902 encryption_required = x->global->encryption_required;
1904 if (opcode == SMB2_OP_SESSSETUP &&
1905 x->global->channels[0].signing_key.length) {
1906 signing_required = true;
1910 req->do_signing = false;
1911 req->do_encryption = false;
1912 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1913 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1914 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1916 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1917 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1918 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1919 (unsigned long long)x->global->session_wire_id,
1920 (unsigned long long)tf_session_id));
1922 * TODO: windows allows this...
1923 * should we drop the connection?
1925 * For now we just return ACCESS_DENIED
1926 * (Windows clients never trigger this)
1927 * and wait for an update of [MS-SMB2].
1929 return smbd_smb2_request_error(req,
1930 NT_STATUS_ACCESS_DENIED);
1933 req->do_encryption = true;
1936 if (encryption_required && !req->do_encryption) {
1937 return smbd_smb2_request_error(req,
1938 NT_STATUS_ACCESS_DENIED);
1941 call = smbd_smb2_call(opcode);
1942 if (call == NULL) {
1943 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1946 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1947 SMB2_HDR_FLAG_SIGNED |
1948 SMB2_HDR_FLAG_DFS;
1949 if (opcode == SMB2_OP_CANCEL) {
1950 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1952 if ((flags & ~allowed_flags) != 0) {
1953 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1956 if (flags & SMB2_HDR_FLAG_CHAINED) {
1958 * This check is mostly for giving the correct error code
1959 * for compounded requests.
1961 if (!NT_STATUS_IS_OK(session_status)) {
1962 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1964 } else {
1965 req->compat_chain_fsp = NULL;
1968 if (req->do_encryption) {
1969 signing_required = false;
1970 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1971 DATA_BLOB signing_key;
1973 if (x == NULL) {
1974 return smbd_smb2_request_error(
1975 req, NT_STATUS_ACCESS_DENIED);
1978 signing_key = x->global->channels[0].signing_key;
1981 * If we have a signing key, we should
1982 * sign the response
1984 if (signing_key.length > 0) {
1985 req->do_signing = true;
1988 status = smb2_signing_check_pdu(signing_key,
1989 conn->protocol,
1990 SMBD_SMB2_IN_HDR_IOV(req),
1991 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1992 if (!NT_STATUS_IS_OK(status)) {
1993 return smbd_smb2_request_error(req, status);
1997 * Now that we know the request was correctly signed
1998 * we have to sign the response too.
2000 req->do_signing = true;
2002 if (!NT_STATUS_IS_OK(session_status)) {
2003 return smbd_smb2_request_error(req, session_status);
2005 } else if (opcode == SMB2_OP_CANCEL) {
2006 /* Cancel requests are allowed to skip the signing */
2007 } else if (signing_required) {
2009 * If signing is required we try to sign
2010 * a possible error response
2012 req->do_signing = true;
2013 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2016 if (flags & SMB2_HDR_FLAG_CHAINED) {
2017 req->compound_related = true;
2018 req->sconn->smb2.compound_related_in_progress = true;
2021 if (call->need_session) {
2022 if (!NT_STATUS_IS_OK(session_status)) {
2023 return smbd_smb2_request_error(req, session_status);
2027 if (call->need_tcon) {
2028 SMB_ASSERT(call->need_session);
2031 * This call needs to be run as user.
2033 * smbd_smb2_request_check_tcon()
2034 * calls change_to_user() on success.
2036 status = smbd_smb2_request_check_tcon(req);
2037 if (!NT_STATUS_IS_OK(status)) {
2038 return smbd_smb2_request_error(req, status);
2040 if (req->tcon->global->encryption_required) {
2041 encryption_required = true;
2043 if (encryption_required && !req->do_encryption) {
2044 return smbd_smb2_request_error(req,
2045 NT_STATUS_ACCESS_DENIED);
2049 if (call->fileid_ofs != 0) {
2050 size_t needed = call->fileid_ofs + 16;
2051 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2052 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2053 uint64_t file_id_persistent;
2054 uint64_t file_id_volatile;
2055 struct files_struct *fsp;
2057 SMB_ASSERT(call->need_tcon);
2059 if (needed > body_size) {
2060 return smbd_smb2_request_error(req,
2061 NT_STATUS_INVALID_PARAMETER);
2064 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2065 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2067 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2068 if (fsp == NULL) {
2069 if (!call->allow_invalid_fileid) {
2070 return smbd_smb2_request_error(req,
2071 NT_STATUS_FILE_CLOSED);
2074 if (file_id_persistent != UINT64_MAX) {
2075 return smbd_smb2_request_error(req,
2076 NT_STATUS_FILE_CLOSED);
2078 if (file_id_volatile != UINT64_MAX) {
2079 return smbd_smb2_request_error(req,
2080 NT_STATUS_FILE_CLOSED);
2085 if (call->as_root) {
2086 SMB_ASSERT(call->fileid_ofs == 0);
2087 /* This call needs to be run as root */
2088 change_to_root_user();
2089 } else {
2090 SMB_ASSERT(call->need_tcon);
2093 switch (opcode) {
2094 case SMB2_OP_NEGPROT:
2096 START_PROFILE(smb2_negprot);
2097 return_value = smbd_smb2_request_process_negprot(req);
2098 END_PROFILE(smb2_negprot);
2100 break;
2102 case SMB2_OP_SESSSETUP:
2104 START_PROFILE(smb2_sesssetup);
2105 return_value = smbd_smb2_request_process_sesssetup(req);
2106 END_PROFILE(smb2_sesssetup);
2108 break;
2110 case SMB2_OP_LOGOFF:
2112 START_PROFILE(smb2_logoff);
2113 return_value = smbd_smb2_request_process_logoff(req);
2114 END_PROFILE(smb2_logoff);
2116 break;
2118 case SMB2_OP_TCON:
2120 START_PROFILE(smb2_tcon);
2121 return_value = smbd_smb2_request_process_tcon(req);
2122 END_PROFILE(smb2_tcon);
2124 break;
2126 case SMB2_OP_TDIS:
2128 START_PROFILE(smb2_tdis);
2129 return_value = smbd_smb2_request_process_tdis(req);
2130 END_PROFILE(smb2_tdis);
2132 break;
2134 case SMB2_OP_CREATE:
2136 START_PROFILE(smb2_create);
2137 return_value = smbd_smb2_request_process_create(req);
2138 END_PROFILE(smb2_create);
2140 break;
2142 case SMB2_OP_CLOSE:
2144 START_PROFILE(smb2_close);
2145 return_value = smbd_smb2_request_process_close(req);
2146 END_PROFILE(smb2_close);
2148 break;
2150 case SMB2_OP_FLUSH:
2152 START_PROFILE(smb2_flush);
2153 return_value = smbd_smb2_request_process_flush(req);
2154 END_PROFILE(smb2_flush);
2156 break;
2158 case SMB2_OP_READ:
2160 START_PROFILE(smb2_read);
2161 return_value = smbd_smb2_request_process_read(req);
2162 END_PROFILE(smb2_read);
2164 break;
2166 case SMB2_OP_WRITE:
2168 START_PROFILE(smb2_write);
2169 return_value = smbd_smb2_request_process_write(req);
2170 END_PROFILE(smb2_write);
2172 break;
2174 case SMB2_OP_LOCK:
2176 START_PROFILE(smb2_lock);
2177 return_value = smbd_smb2_request_process_lock(req);
2178 END_PROFILE(smb2_lock);
2180 break;
2182 case SMB2_OP_IOCTL:
2184 START_PROFILE(smb2_ioctl);
2185 return_value = smbd_smb2_request_process_ioctl(req);
2186 END_PROFILE(smb2_ioctl);
2188 break;
2190 case SMB2_OP_CANCEL:
2192 START_PROFILE(smb2_cancel);
2193 return_value = smbd_smb2_request_process_cancel(req);
2194 END_PROFILE(smb2_cancel);
2196 break;
2198 case SMB2_OP_KEEPALIVE:
2200 START_PROFILE(smb2_keepalive);
2201 return_value = smbd_smb2_request_process_keepalive(req);
2202 END_PROFILE(smb2_keepalive);
2204 break;
2206 case SMB2_OP_FIND:
2208 START_PROFILE(smb2_find);
2209 return_value = smbd_smb2_request_process_find(req);
2210 END_PROFILE(smb2_find);
2212 break;
2214 case SMB2_OP_NOTIFY:
2216 START_PROFILE(smb2_notify);
2217 return_value = smbd_smb2_request_process_notify(req);
2218 END_PROFILE(smb2_notify);
2220 break;
2222 case SMB2_OP_GETINFO:
2224 START_PROFILE(smb2_getinfo);
2225 return_value = smbd_smb2_request_process_getinfo(req);
2226 END_PROFILE(smb2_getinfo);
2228 break;
2230 case SMB2_OP_SETINFO:
2232 START_PROFILE(smb2_setinfo);
2233 return_value = smbd_smb2_request_process_setinfo(req);
2234 END_PROFILE(smb2_setinfo);
2236 break;
2238 case SMB2_OP_BREAK:
2240 START_PROFILE(smb2_break);
2241 return_value = smbd_smb2_request_process_break(req);
2242 END_PROFILE(smb2_break);
2244 break;
2246 default:
2247 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2248 break;
2250 return return_value;
2253 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2255 struct smbXsrv_connection *conn = req->sconn->conn;
2256 struct tevent_req *subreq;
2257 int first_idx = 1;
2258 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2259 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2260 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2262 req->subreq = NULL;
2263 TALLOC_FREE(req->async_te);
2265 if (req->do_encryption &&
2266 (firsttf->iov_len == 0) &&
2267 (req->first_key.length == 0) &&
2268 (req->session != NULL) &&
2269 (req->session->global->encryption_key.length != 0))
2271 DATA_BLOB encryption_key = req->session->global->encryption_key;
2272 uint8_t *tf;
2273 uint64_t session_id = req->session->global->session_wire_id;
2274 struct smbXsrv_session *x = req->session;
2275 uint64_t nonce_high;
2276 uint64_t nonce_low;
2278 nonce_high = x->nonce_high;
2279 nonce_low = x->nonce_low;
2281 x->nonce_low += 1;
2282 if (x->nonce_low == 0) {
2283 x->nonce_low += 1;
2284 x->nonce_high += 1;
2288 * We need to place the SMB2_TRANSFORM header before the
2289 * first SMB2 header
2293 * we need to remember the encryption key
2294 * and defer the signing/encryption until
2295 * we are sure that we do not change
2296 * the header again.
2298 req->first_key = data_blob_dup_talloc(req, encryption_key);
2299 if (req->first_key.data == NULL) {
2300 return NT_STATUS_NO_MEMORY;
2303 tf = talloc_zero_array(req->out.vector, uint8_t,
2304 SMB2_TF_HDR_SIZE);
2305 if (tf == NULL) {
2306 return NT_STATUS_NO_MEMORY;
2309 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2310 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2311 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2312 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2314 firsttf->iov_base = (void *)tf;
2315 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2318 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2319 (req->last_key.length > 0) &&
2320 (firsttf->iov_len == 0))
2322 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2323 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2324 NTSTATUS status;
2327 * As we are sure the header of the last request in the
2328 * compound chain will not change, we can to sign here
2329 * with the last signing key we remembered.
2331 status = smb2_signing_sign_pdu(req->last_key,
2332 conn->protocol,
2333 lasthdr,
2334 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2335 if (!NT_STATUS_IS_OK(status)) {
2336 return status;
2339 data_blob_clear_free(&req->last_key);
2341 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2343 if (req->current_idx < req->out.vector_count) {
2345 * We must process the remaining compound
2346 * SMB2 requests before any new incoming SMB2
2347 * requests. This is because incoming SMB2
2348 * requests may include a cancel for a
2349 * compound request we haven't processed
2350 * yet.
2352 struct tevent_immediate *im = tevent_create_immediate(req);
2353 if (!im) {
2354 return NT_STATUS_NO_MEMORY;
2357 if (req->do_signing && firsttf->iov_len == 0) {
2358 struct smbXsrv_session *x = req->session;
2359 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2362 * we need to remember the signing key
2363 * and defer the signing until
2364 * we are sure that we do not change
2365 * the header again.
2367 req->last_key = data_blob_dup_talloc(req, signing_key);
2368 if (req->last_key.data == NULL) {
2369 return NT_STATUS_NO_MEMORY;
2373 tevent_schedule_immediate(im,
2374 req->sconn->ev_ctx,
2375 smbd_smb2_request_dispatch_immediate,
2376 req);
2377 return NT_STATUS_OK;
2380 if (req->compound_related) {
2381 req->compound_related = false;
2382 req->sconn->smb2.compound_related_in_progress = false;
2385 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2387 /* Set credit for these operations (zero credits if this
2388 is a final reply for an async operation). */
2389 smb2_calculate_credits(req, req);
2392 * now check if we need to sign the current response
2394 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2395 NTSTATUS status;
2397 status = smb2_signing_encrypt_pdu(req->first_key,
2398 conn->protocol,
2399 firsttf,
2400 req->out.vector_count - first_idx);
2401 if (!NT_STATUS_IS_OK(status)) {
2402 return status;
2404 } else if (req->do_signing) {
2405 NTSTATUS status;
2406 struct smbXsrv_session *x = req->session;
2407 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2409 status = smb2_signing_sign_pdu(signing_key,
2410 conn->protocol,
2411 outhdr,
2412 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2413 if (!NT_STATUS_IS_OK(status)) {
2414 return status;
2417 data_blob_clear_free(&req->first_key);
2419 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2420 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2421 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2422 /* Dynamic part is NULL. Chop it off,
2423 We're going to send it via sendfile. */
2424 req->out.vector_count -= 1;
2427 subreq = tstream_writev_queue_send(req,
2428 req->sconn->ev_ctx,
2429 req->sconn->smb2.stream,
2430 req->sconn->smb2.send_queue,
2431 req->out.vector,
2432 req->out.vector_count);
2433 if (subreq == NULL) {
2434 return NT_STATUS_NO_MEMORY;
2436 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
2438 * We're done with this request -
2439 * move it off the "being processed" queue.
2441 DLIST_REMOVE(req->sconn->smb2.requests, req);
2443 return NT_STATUS_OK;
2446 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2448 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2449 struct tevent_immediate *im,
2450 void *private_data)
2452 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2453 struct smbd_smb2_request);
2454 struct smbd_server_connection *sconn = req->sconn;
2455 NTSTATUS status;
2457 TALLOC_FREE(im);
2459 if (DEBUGLEVEL >= 10) {
2460 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2461 req->current_idx, req->in.vector_count));
2462 print_req_vectors(req);
2465 status = smbd_smb2_request_dispatch(req);
2466 if (!NT_STATUS_IS_OK(status)) {
2467 smbd_server_connection_terminate(sconn, nt_errstr(status));
2468 return;
2471 status = smbd_smb2_request_next_incoming(sconn);
2472 if (!NT_STATUS_IS_OK(status)) {
2473 smbd_server_connection_terminate(sconn, nt_errstr(status));
2474 return;
2478 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
2480 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
2481 struct smbd_smb2_request);
2482 struct smbd_server_connection *sconn = req->sconn;
2483 int ret;
2484 int sys_errno;
2485 NTSTATUS status;
2487 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2488 TALLOC_FREE(subreq);
2489 TALLOC_FREE(req);
2490 if (ret == -1) {
2491 status = map_nt_error_from_unix(sys_errno);
2492 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
2493 nt_errstr(status)));
2494 smbd_server_connection_terminate(sconn, nt_errstr(status));
2495 return;
2498 status = smbd_smb2_request_next_incoming(sconn);
2499 if (!NT_STATUS_IS_OK(status)) {
2500 smbd_server_connection_terminate(sconn, nt_errstr(status));
2501 return;
2505 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2506 NTSTATUS status,
2507 DATA_BLOB body, DATA_BLOB *dyn,
2508 const char *location)
2510 uint8_t *outhdr;
2511 struct iovec *outbody_v;
2512 struct iovec *outdyn_v;
2513 uint32_t next_command_ofs;
2515 DEBUG(10,("smbd_smb2_request_done_ex: "
2516 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2517 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2518 dyn ? "yes": "no",
2519 (unsigned int)(dyn ? dyn->length : 0),
2520 location));
2522 if (body.length < 2) {
2523 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2526 if ((body.length % 2) != 0) {
2527 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2530 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2531 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2532 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2534 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2535 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2537 outbody_v->iov_base = (void *)body.data;
2538 outbody_v->iov_len = body.length;
2540 if (dyn) {
2541 outdyn_v->iov_base = (void *)dyn->data;
2542 outdyn_v->iov_len = dyn->length;
2543 } else {
2544 outdyn_v->iov_base = NULL;
2545 outdyn_v->iov_len = 0;
2548 /* see if we need to recalculate the offset to the next response */
2549 if (next_command_ofs > 0) {
2550 next_command_ofs = SMB2_HDR_BODY;
2551 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2552 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2555 if ((next_command_ofs % 8) != 0) {
2556 size_t pad_size = 8 - (next_command_ofs % 8);
2557 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2559 * if the dyn buffer is empty
2560 * we can use it to add padding
2562 uint8_t *pad;
2564 pad = talloc_zero_array(req->out.vector,
2565 uint8_t, pad_size);
2566 if (pad == NULL) {
2567 return smbd_smb2_request_error(req,
2568 NT_STATUS_NO_MEMORY);
2571 outdyn_v->iov_base = (void *)pad;
2572 outdyn_v->iov_len = pad_size;
2573 } else {
2575 * For now we copy the dynamic buffer
2576 * and add the padding to the new buffer
2578 size_t old_size;
2579 uint8_t *old_dyn;
2580 size_t new_size;
2581 uint8_t *new_dyn;
2583 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2584 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2586 new_size = old_size + pad_size;
2587 new_dyn = talloc_zero_array(req->out.vector,
2588 uint8_t, new_size);
2589 if (new_dyn == NULL) {
2590 return smbd_smb2_request_error(req,
2591 NT_STATUS_NO_MEMORY);
2594 memcpy(new_dyn, old_dyn, old_size);
2595 memset(new_dyn + old_size, 0, pad_size);
2597 outdyn_v->iov_base = (void *)new_dyn;
2598 outdyn_v->iov_len = new_size;
2600 next_command_ofs += pad_size;
2603 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2605 return smbd_smb2_request_reply(req);
2608 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2609 NTSTATUS status,
2610 DATA_BLOB *info,
2611 const char *location)
2613 DATA_BLOB body;
2614 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2616 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2617 req->current_idx, nt_errstr(status), info ? " +info" : "",
2618 location));
2620 body.data = outhdr + SMB2_HDR_BODY;
2621 body.length = 8;
2622 SSVAL(body.data, 0, 9);
2624 if (info) {
2625 SIVAL(body.data, 0x04, info->length);
2626 } else {
2627 /* Allocated size of req->out.vector[i].iov_base
2628 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2629 * 1 byte without having to do an alloc.
2631 info = talloc_zero_array(req->out.vector,
2632 DATA_BLOB,
2634 if (!info) {
2635 return NT_STATUS_NO_MEMORY;
2637 info->data = ((uint8_t *)outhdr) +
2638 OUTVEC_ALLOC_SIZE - 1;
2639 info->length = 1;
2640 SCVAL(info->data, 0, 0);
2644 * Note: Even if there is an error, continue to process the request.
2645 * per MS-SMB2.
2648 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2652 struct smbd_smb2_send_oplock_break_state {
2653 struct smbd_server_connection *sconn;
2654 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18];
2655 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2658 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
2660 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2661 struct smbXsrv_session *session,
2662 struct smbXsrv_tcon *tcon,
2663 struct smbXsrv_open *op,
2664 uint8_t oplock_level)
2666 struct smbd_smb2_send_oplock_break_state *state;
2667 struct smbXsrv_connection *conn = sconn->conn;
2668 struct tevent_req *subreq;
2669 uint8_t *tf;
2670 size_t tf_len;
2671 uint8_t *hdr;
2672 uint8_t *body;
2673 size_t body_len;
2674 uint8_t *dyn;
2675 size_t dyn_len;
2676 bool do_encryption = session->global->encryption_required;
2677 uint64_t nonce_high = 0;
2678 uint64_t nonce_low = 0;
2680 if (tcon->global->encryption_required) {
2681 do_encryption = true;
2684 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2685 if (state == NULL) {
2686 return NT_STATUS_NO_MEMORY;
2688 state->sconn = sconn;
2690 tf = state->buf + NBT_HDR_SIZE;
2691 tf_len = SMB2_TF_HDR_SIZE;
2692 hdr = tf + tf_len;
2693 body = hdr + SMB2_HDR_BODY;
2694 body_len = 0x18;
2695 dyn = body + body_len;
2696 dyn_len = 0;
2698 if (do_encryption) {
2699 nonce_high = session->nonce_high;
2700 nonce_low = session->nonce_low;
2702 session->nonce_low += 1;
2703 if (session->nonce_low == 0) {
2704 session->nonce_low += 1;
2705 session->nonce_high += 1;
2709 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2710 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2711 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2712 SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
2714 SIVAL(hdr, 0, SMB2_MAGIC);
2715 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2716 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2717 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2718 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2719 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2720 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2721 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2722 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2723 SIVAL(hdr, SMB2_HDR_PID, 0);
2724 SIVAL(hdr, SMB2_HDR_TID, 0);
2725 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2726 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2728 SSVAL(body, 0x00, body_len);
2730 SCVAL(body, 0x02, oplock_level);
2731 SCVAL(body, 0x03, 0); /* reserved */
2732 SIVAL(body, 0x04, 0); /* reserved */
2733 SBVAL(body, 0x08, op->global->open_persistent_id);
2734 SBVAL(body, 0x10, op->global->open_volatile_id);
2736 state->vector[0].iov_base = (void *)state->buf;
2737 state->vector[0].iov_len = NBT_HDR_SIZE;
2739 if (do_encryption) {
2740 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
2741 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
2742 } else {
2743 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
2744 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
2747 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
2748 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
2750 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
2751 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = body_len;
2753 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
2754 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_len;
2756 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2758 if (do_encryption) {
2759 NTSTATUS status;
2760 DATA_BLOB encryption_key = session->global->encryption_key;
2762 status = smb2_signing_encrypt_pdu(encryption_key,
2763 conn->protocol,
2764 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2765 SMBD_SMB2_NUM_IOV_PER_REQ);
2766 if (!NT_STATUS_IS_OK(status)) {
2767 return status;
2771 subreq = tstream_writev_queue_send(state,
2772 sconn->ev_ctx,
2773 sconn->smb2.stream,
2774 sconn->smb2.send_queue,
2775 state->vector,
2776 ARRAY_SIZE(state->vector));
2777 if (subreq == NULL) {
2778 return NT_STATUS_NO_MEMORY;
2780 tevent_req_set_callback(subreq,
2781 smbd_smb2_oplock_break_writev_done,
2782 state);
2784 return NT_STATUS_OK;
2787 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
2789 struct smbd_smb2_send_oplock_break_state *state =
2790 tevent_req_callback_data(subreq,
2791 struct smbd_smb2_send_oplock_break_state);
2792 struct smbd_server_connection *sconn = state->sconn;
2793 int ret;
2794 int sys_errno;
2796 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2797 TALLOC_FREE(subreq);
2798 if (ret == -1) {
2799 NTSTATUS status = map_nt_error_from_unix(sys_errno);
2800 smbd_server_connection_terminate(sconn, nt_errstr(status));
2801 return;
2804 TALLOC_FREE(state);
2807 struct smbd_smb2_request_read_state {
2808 struct tevent_context *ev;
2809 struct smbd_server_connection *sconn;
2810 struct smbd_smb2_request *smb2_req;
2811 struct {
2812 uint8_t nbt[NBT_HDR_SIZE];
2813 bool done;
2814 } hdr;
2815 size_t pktlen;
2816 uint8_t *pktbuf;
2819 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2820 void *private_data,
2821 TALLOC_CTX *mem_ctx,
2822 struct iovec **_vector,
2823 size_t *_count);
2824 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
2826 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
2827 struct tevent_context *ev,
2828 struct smbd_server_connection *sconn)
2830 struct tevent_req *req;
2831 struct smbd_smb2_request_read_state *state;
2832 struct tevent_req *subreq;
2834 req = tevent_req_create(mem_ctx, &state,
2835 struct smbd_smb2_request_read_state);
2836 if (req == NULL) {
2837 return NULL;
2839 state->ev = ev;
2840 state->sconn = sconn;
2842 state->smb2_req = smbd_smb2_request_allocate(state);
2843 if (tevent_req_nomem(state->smb2_req, req)) {
2844 return tevent_req_post(req, ev);
2846 state->smb2_req->sconn = sconn;
2848 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2849 state->ev,
2850 state->sconn->smb2.stream,
2851 state->sconn->smb2.recv_queue,
2852 smbd_smb2_request_next_vector,
2853 state);
2854 if (tevent_req_nomem(subreq, req)) {
2855 return tevent_req_post(req, ev);
2857 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2859 return req;
2862 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
2863 void *private_data,
2864 TALLOC_CTX *mem_ctx,
2865 struct iovec **_vector,
2866 size_t *_count)
2868 struct smbd_smb2_request_read_state *state =
2869 talloc_get_type_abort(private_data,
2870 struct smbd_smb2_request_read_state);
2871 struct iovec *vector;
2873 if (state->pktlen > 0) {
2874 /* if there're no remaining bytes, we're done */
2875 *_vector = NULL;
2876 *_count = 0;
2877 return 0;
2880 if (!state->hdr.done) {
2882 * first we need to get the NBT header
2884 vector = talloc_array(mem_ctx, struct iovec, 1);
2885 if (vector == NULL) {
2886 return -1;
2889 vector[0].iov_base = (void *)state->hdr.nbt;
2890 vector[0].iov_len = NBT_HDR_SIZE;
2892 *_vector = vector;
2893 *_count = 1;
2895 state->hdr.done = true;
2896 return 0;
2900 * Now we analyze the NBT header
2902 state->pktlen = smb2_len(state->hdr.nbt);
2904 if (state->pktlen == 0) {
2905 /* if there're no remaining bytes, we're done */
2906 *_vector = NULL;
2907 *_count = 0;
2908 return 0;
2911 state->pktbuf = talloc_array(state->smb2_req, uint8_t, state->pktlen);
2912 if (state->pktbuf == NULL) {
2913 return -1;
2916 vector = talloc_array(mem_ctx, struct iovec, 1);
2917 if (vector == NULL) {
2918 return -1;
2921 vector[0].iov_base = (void *)state->pktbuf;
2922 vector[0].iov_len = state->pktlen;
2924 *_vector = vector;
2925 *_count = 1;
2926 return 0;
2929 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
2931 struct tevent_req *req =
2932 tevent_req_callback_data(subreq,
2933 struct tevent_req);
2934 struct smbd_smb2_request_read_state *state =
2935 tevent_req_data(req,
2936 struct smbd_smb2_request_read_state);
2937 int ret;
2938 int sys_errno;
2939 NTSTATUS status;
2940 NTTIME now;
2942 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
2943 TALLOC_FREE(subreq);
2944 if (ret == -1) {
2945 status = map_nt_error_from_unix(sys_errno);
2946 tevent_req_nterror(req, status);
2947 return;
2950 if (state->hdr.nbt[0] != 0x00) {
2951 DEBUG(1,("smbd_smb2_request_read_done: ignore NBT[0x%02X] msg\n",
2952 state->hdr.nbt[0]));
2954 ZERO_STRUCT(state->hdr);
2955 TALLOC_FREE(state->pktbuf);
2956 state->pktlen = 0;
2958 subreq = tstream_readv_pdu_queue_send(state->smb2_req,
2959 state->ev,
2960 state->sconn->smb2.stream,
2961 state->sconn->smb2.recv_queue,
2962 smbd_smb2_request_next_vector,
2963 state);
2964 if (tevent_req_nomem(subreq, req)) {
2965 return;
2967 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
2968 return;
2971 state->smb2_req->request_time = timeval_current();
2972 now = timeval_to_nttime(&state->smb2_req->request_time);
2974 status = smbd_smb2_inbuf_parse_compound(state->smb2_req->sconn->conn,
2975 now,
2976 state->pktbuf,
2977 state->pktlen,
2978 state->smb2_req,
2979 &state->smb2_req->in.vector,
2980 &state->smb2_req->in.vector_count);
2981 if (tevent_req_nterror(req, status)) {
2982 return;
2985 state->smb2_req->current_idx = 1;
2987 tevent_req_done(req);
2990 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
2991 TALLOC_CTX *mem_ctx,
2992 struct smbd_smb2_request **_smb2_req)
2994 struct smbd_smb2_request_read_state *state =
2995 tevent_req_data(req,
2996 struct smbd_smb2_request_read_state);
2997 NTSTATUS status;
2999 if (tevent_req_is_nterror(req, &status)) {
3000 tevent_req_received(req);
3001 return status;
3004 *_smb2_req = talloc_move(mem_ctx, &state->smb2_req);
3005 tevent_req_received(req);
3006 return NT_STATUS_OK;
3009 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
3011 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
3013 size_t max_send_queue_len;
3014 size_t cur_send_queue_len;
3015 struct tevent_req *subreq;
3017 if (sconn->smb2.compound_related_in_progress) {
3019 * Can't read another until the related
3020 * compound is done.
3022 return NT_STATUS_OK;
3025 if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
3027 * if there is already a smbd_smb2_request_read
3028 * pending, we are done.
3030 return NT_STATUS_OK;
3033 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
3034 cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
3036 if (cur_send_queue_len > max_send_queue_len) {
3038 * if we have a lot of requests to send,
3039 * we wait until they are on the wire until we
3040 * ask for the next request.
3042 return NT_STATUS_OK;
3045 /* ask for the next request */
3046 subreq = smbd_smb2_request_read_send(sconn, sconn->ev_ctx, sconn);
3047 if (subreq == NULL) {
3048 return NT_STATUS_NO_MEMORY;
3050 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
3052 return NT_STATUS_OK;
3055 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
3056 uint8_t *inbuf, size_t size)
3058 NTSTATUS status;
3059 struct smbd_smb2_request *req = NULL;
3061 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
3062 (unsigned int)size));
3064 status = smbd_initialize_smb2(sconn);
3065 if (!NT_STATUS_IS_OK(status)) {
3066 smbd_server_connection_terminate(sconn, nt_errstr(status));
3067 return;
3070 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
3071 if (!NT_STATUS_IS_OK(status)) {
3072 smbd_server_connection_terminate(sconn, nt_errstr(status));
3073 return;
3076 status = smbd_smb2_request_validate(req);
3077 if (!NT_STATUS_IS_OK(status)) {
3078 smbd_server_connection_terminate(sconn, nt_errstr(status));
3079 return;
3082 status = smbd_smb2_request_setup_out(req);
3083 if (!NT_STATUS_IS_OK(status)) {
3084 smbd_server_connection_terminate(sconn, nt_errstr(status));
3085 return;
3088 status = smbd_smb2_request_dispatch(req);
3089 if (!NT_STATUS_IS_OK(status)) {
3090 smbd_server_connection_terminate(sconn, nt_errstr(status));
3091 return;
3094 status = smbd_smb2_request_next_incoming(sconn);
3095 if (!NT_STATUS_IS_OK(status)) {
3096 smbd_server_connection_terminate(sconn, nt_errstr(status));
3097 return;
3100 sconn->num_requests++;
3103 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
3105 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
3106 struct smbd_server_connection);
3107 NTSTATUS status;
3108 struct smbd_smb2_request *req = NULL;
3110 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
3111 TALLOC_FREE(subreq);
3112 if (!NT_STATUS_IS_OK(status)) {
3113 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
3114 nt_errstr(status)));
3115 smbd_server_connection_terminate(sconn, nt_errstr(status));
3116 return;
3119 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
3120 req->current_idx, req->in.vector_count));
3122 status = smbd_smb2_request_validate(req);
3123 if (!NT_STATUS_IS_OK(status)) {
3124 smbd_server_connection_terminate(sconn, nt_errstr(status));
3125 return;
3128 status = smbd_smb2_request_setup_out(req);
3129 if (!NT_STATUS_IS_OK(status)) {
3130 smbd_server_connection_terminate(sconn, nt_errstr(status));
3131 return;
3134 status = smbd_smb2_request_dispatch(req);
3135 if (!NT_STATUS_IS_OK(status)) {
3136 smbd_server_connection_terminate(sconn, nt_errstr(status));
3137 return;
3140 status = smbd_smb2_request_next_incoming(sconn);
3141 if (!NT_STATUS_IS_OK(status)) {
3142 smbd_server_connection_terminate(sconn, nt_errstr(status));
3143 return;
3146 sconn->num_requests++;
3148 /* The timeout_processing function isn't run nearly
3149 often enough to implement 'max log size' without
3150 overrunning the size of the file by many megabytes.
3151 This is especially true if we are running at debug
3152 level 10. Checking every 50 SMB2s is a nice
3153 tradeoff of performance vs log file size overrun. */
3155 if ((sconn->num_requests % 50) == 0 &&
3156 need_to_check_log_size()) {
3157 change_to_root_user();
3158 check_log_size();