auth: Make sure that creds_out is initialized with NULL.
[Samba.git] / source3 / smbd / smb2_server.c
blobb46f9944a1619c2f0721f5107a501fb66e74f27b
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "../lib/util/tevent_ntstatus.h"
28 #include "smbprofile.h"
29 #include "../lib/util/bitmap.h"
30 #include "../librpc/gen_ndr/krb5pac.h"
31 #include "auth.h"
33 static void smbd_smb2_connection_handler(struct tevent_context *ev,
34 struct tevent_fd *fde,
35 uint16_t flags,
36 void *private_data);
37 static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn,
38 uint16_t fde_flags);
40 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
42 static const struct smbd_smb2_dispatch_table {
43 uint16_t opcode;
44 const char *name;
45 bool need_session;
46 bool need_tcon;
47 bool as_root;
48 uint16_t fileid_ofs;
49 bool allow_invalid_fileid;
50 } smbd_smb2_table[] = {
51 #define _OP(o) .opcode = o, .name = #o
53 _OP(SMB2_OP_NEGPROT),
54 .as_root = true,
55 },{
56 _OP(SMB2_OP_SESSSETUP),
57 .as_root = true,
58 },{
59 _OP(SMB2_OP_LOGOFF),
60 .need_session = true,
61 .as_root = true,
62 },{
63 _OP(SMB2_OP_TCON),
64 .need_session = true,
66 * This call needs to be run as root.
68 * smbd_smb2_request_process_tcon()
69 * calls make_connection_snum(), which will call
70 * change_to_user(), when needed.
72 .as_root = true,
73 },{
74 _OP(SMB2_OP_TDIS),
75 .need_session = true,
76 .need_tcon = true,
77 .as_root = true,
78 },{
79 _OP(SMB2_OP_CREATE),
80 .need_session = true,
81 .need_tcon = true,
82 },{
83 _OP(SMB2_OP_CLOSE),
84 .need_session = true,
85 .need_tcon = true,
86 .fileid_ofs = 0x08,
87 },{
88 _OP(SMB2_OP_FLUSH),
89 .need_session = true,
90 .need_tcon = true,
91 .fileid_ofs = 0x08,
92 },{
93 _OP(SMB2_OP_READ),
94 .need_session = true,
95 .need_tcon = true,
96 .fileid_ofs = 0x10,
97 },{
98 _OP(SMB2_OP_WRITE),
99 .need_session = true,
100 .need_tcon = true,
101 .fileid_ofs = 0x10,
103 _OP(SMB2_OP_LOCK),
104 .need_session = true,
105 .need_tcon = true,
106 .fileid_ofs = 0x08,
108 _OP(SMB2_OP_IOCTL),
109 .need_session = true,
110 .need_tcon = true,
111 .fileid_ofs = 0x08,
112 .allow_invalid_fileid = true,
114 _OP(SMB2_OP_CANCEL),
115 .as_root = true,
117 _OP(SMB2_OP_KEEPALIVE),
118 .as_root = true,
120 _OP(SMB2_OP_FIND),
121 .need_session = true,
122 .need_tcon = true,
123 .fileid_ofs = 0x08,
125 _OP(SMB2_OP_NOTIFY),
126 .need_session = true,
127 .need_tcon = true,
128 .fileid_ofs = 0x08,
130 _OP(SMB2_OP_GETINFO),
131 .need_session = true,
132 .need_tcon = true,
133 .fileid_ofs = 0x18,
135 _OP(SMB2_OP_SETINFO),
136 .need_session = true,
137 .need_tcon = true,
138 .fileid_ofs = 0x10,
140 _OP(SMB2_OP_BREAK),
141 .need_session = true,
142 .need_tcon = true,
144 * we do not set
145 * .fileid_ofs here
146 * as LEASE breaks does not
147 * have a file id
152 const char *smb2_opcode_name(uint16_t opcode)
154 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
155 return "Bad SMB2 opcode";
157 return smbd_smb2_table[opcode].name;
160 static const struct smbd_smb2_dispatch_table *smbd_smb2_call(uint16_t opcode)
162 const struct smbd_smb2_dispatch_table *ret = NULL;
164 if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
165 return NULL;
168 ret = &smbd_smb2_table[opcode];
170 SMB_ASSERT(ret->opcode == opcode);
172 return ret;
175 static void print_req_vectors(const struct smbd_smb2_request *req)
177 int i;
179 for (i = 0; i < req->in.vector_count; i++) {
180 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
181 (unsigned int)i,
182 (unsigned int)req->in.vector[i].iov_len);
184 for (i = 0; i < req->out.vector_count; i++) {
185 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
186 (unsigned int)i,
187 (unsigned int)req->out.vector[i].iov_len);
191 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
193 if (size < (4 + SMB2_HDR_BODY)) {
194 return false;
197 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
198 return false;
201 return true;
204 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
206 TALLOC_FREE(sconn->smb1.fde);
208 sconn->smb2.send_queue = NULL;
210 sconn->smb2.seqnum_low = 0;
211 sconn->smb2.seqnum_range = 1;
212 sconn->smb2.credits_granted = 1;
213 sconn->smb2.max_credits = lp_smb2_max_credits();
214 sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
215 sconn->smb2.max_credits);
216 if (sconn->smb2.credits_bitmap == NULL) {
217 return NT_STATUS_NO_MEMORY;
220 sconn->smb2.fde = tevent_add_fd(sconn->ev_ctx,
221 sconn,
222 sconn->sock,
223 TEVENT_FD_READ,
224 smbd_smb2_connection_handler,
225 sconn);
226 if (sconn->smb2.fde == NULL) {
227 return NT_STATUS_NO_MEMORY;
230 /* Ensure child is set to non-blocking mode */
231 set_blocking(sconn->sock, false);
232 return NT_STATUS_OK;
235 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
236 #define _smb2_setlen(_buf,len) do { \
237 uint8_t *buf = (uint8_t *)_buf; \
238 buf[0] = 0; \
239 buf[1] = ((len)&0xFF0000)>>16; \
240 buf[2] = ((len)&0xFF00)>>8; \
241 buf[3] = (len)&0xFF; \
242 } while (0)
244 static void smb2_setup_nbt_length(struct iovec *vector, int count)
246 size_t len = 0;
247 int i;
249 for (i=1; i < count; i++) {
250 len += vector[i].iov_len;
253 _smb2_setlen(vector[0].iov_base, len);
256 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
258 data_blob_clear_free(&req->first_key);
259 data_blob_clear_free(&req->last_key);
260 return 0;
263 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
265 TALLOC_CTX *mem_pool;
266 struct smbd_smb2_request *req;
268 #if 0
269 /* Enable this to find subtle valgrind errors. */
270 mem_pool = talloc_init("smbd_smb2_request_allocate");
271 #else
272 mem_pool = talloc_tos();
273 #endif
274 if (mem_pool == NULL) {
275 return NULL;
278 req = talloc_zero(mem_pool, struct smbd_smb2_request);
279 if (req == NULL) {
280 talloc_free(mem_pool);
281 return NULL;
283 talloc_reparent(mem_pool, mem_ctx, req);
284 #if 0
285 TALLOC_FREE(mem_pool);
286 #endif
288 req->last_session_id = UINT64_MAX;
289 req->last_tid = UINT32_MAX;
291 talloc_set_destructor(req, smbd_smb2_request_destructor);
293 return req;
296 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
297 NTTIME now,
298 uint8_t *buf,
299 size_t buflen,
300 TALLOC_CTX *mem_ctx,
301 struct iovec **piov,
302 int *pnum_iov)
304 struct iovec *iov;
305 int num_iov = 1;
306 size_t taken = 0;
307 uint8_t *first_hdr = buf;
308 size_t verified_buflen = 0;
309 uint8_t *tf = NULL;
310 size_t tf_len = 0;
313 * Note: index '0' is reserved for the transport protocol
315 iov = talloc_zero_array(mem_ctx, struct iovec, num_iov);
316 if (iov == NULL) {
317 return NT_STATUS_NO_MEMORY;
320 while (taken < buflen) {
321 size_t len = buflen - taken;
322 uint8_t *hdr = first_hdr + taken;
323 struct iovec *cur;
324 size_t full_size;
325 size_t next_command_ofs;
326 uint16_t body_size;
327 uint8_t *body = NULL;
328 uint32_t dyn_size;
329 uint8_t *dyn = NULL;
330 struct iovec *iov_tmp;
332 if (verified_buflen > taken) {
333 len = verified_buflen - taken;
334 } else {
335 tf = NULL;
336 tf_len = 0;
339 if (len < 4) {
340 DEBUG(10, ("%d bytes left, expected at least %d\n",
341 (int)len, 4));
342 goto inval;
344 if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
345 struct smbXsrv_session *s = NULL;
346 uint64_t uid;
347 struct iovec tf_iov[2];
348 NTSTATUS status;
349 size_t enc_len;
351 if (conn->protocol < PROTOCOL_SMB2_24) {
352 DEBUG(10, ("Got SMB2_TRANSFORM header, "
353 "but dialect[0x%04X] is used\n",
354 conn->smb2.server.dialect));
355 goto inval;
358 if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) {
359 DEBUG(10, ("Got SMB2_TRANSFORM header, "
360 "but not negotiated "
361 "client[0x%08X] server[0x%08X]\n",
362 conn->smb2.client.capabilities,
363 conn->smb2.server.capabilities));
364 goto inval;
367 if (len < SMB2_TF_HDR_SIZE) {
368 DEBUG(1, ("%d bytes left, expected at least %d\n",
369 (int)len, SMB2_TF_HDR_SIZE));
370 goto inval;
372 tf = hdr;
373 tf_len = SMB2_TF_HDR_SIZE;
374 taken += tf_len;
376 hdr = first_hdr + taken;
377 enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
378 uid = BVAL(tf, SMB2_TF_SESSION_ID);
380 if (len < SMB2_TF_HDR_SIZE + enc_len) {
381 DEBUG(1, ("%d bytes left, expected at least %d\n",
382 (int)len,
383 (int)(SMB2_TF_HDR_SIZE + enc_len)));
384 goto inval;
387 status = smb2srv_session_lookup(conn, uid, now, &s);
388 if (s == NULL) {
389 DEBUG(1, ("invalid session[%llu] in "
390 "SMB2_TRANSFORM header\n",
391 (unsigned long long)uid));
392 TALLOC_FREE(iov);
393 return NT_STATUS_USER_SESSION_DELETED;
396 tf_iov[0].iov_base = (void *)tf;
397 tf_iov[0].iov_len = tf_len;
398 tf_iov[1].iov_base = (void *)hdr;
399 tf_iov[1].iov_len = enc_len;
401 status = smb2_signing_decrypt_pdu(s->global->decryption_key,
402 conn->protocol,
403 tf_iov, 2);
404 if (!NT_STATUS_IS_OK(status)) {
405 TALLOC_FREE(iov);
406 return status;
409 verified_buflen = taken + enc_len;
410 len = enc_len;
414 * We need the header plus the body length field
417 if (len < SMB2_HDR_BODY + 2) {
418 DEBUG(10, ("%d bytes left, expected at least %d\n",
419 (int)len, SMB2_HDR_BODY));
420 goto inval;
422 if (IVAL(hdr, 0) != SMB2_MAGIC) {
423 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
424 IVAL(hdr, 0)));
425 goto inval;
427 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
428 DEBUG(10, ("Got HDR len %d, expected %d\n",
429 SVAL(hdr, 4), SMB2_HDR_BODY));
430 goto inval;
433 full_size = len;
434 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
435 body_size = SVAL(hdr, SMB2_HDR_BODY);
437 if (next_command_ofs != 0) {
438 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
439 goto inval;
441 if (next_command_ofs > full_size) {
442 goto inval;
444 full_size = next_command_ofs;
446 if (body_size < 2) {
447 goto inval;
449 body_size &= 0xfffe;
451 if (body_size > (full_size - SMB2_HDR_BODY)) {
453 * let the caller handle the error
455 body_size = full_size - SMB2_HDR_BODY;
457 body = hdr + SMB2_HDR_BODY;
458 dyn = body + body_size;
459 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
461 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
462 num_iov + SMBD_SMB2_NUM_IOV_PER_REQ);
463 if (iov_tmp == NULL) {
464 TALLOC_FREE(iov);
465 return NT_STATUS_NO_MEMORY;
467 iov = iov_tmp;
468 cur = &iov[num_iov];
469 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
471 cur[SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
472 cur[SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
473 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
474 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
475 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
476 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
477 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
478 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
480 taken += full_size;
483 *piov = iov;
484 *pnum_iov = num_iov;
485 return NT_STATUS_OK;
487 inval:
488 TALLOC_FREE(iov);
489 return NT_STATUS_INVALID_PARAMETER;
492 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
493 uint8_t *inbuf, size_t size,
494 struct smbd_smb2_request **_req)
496 struct smbd_smb2_request *req;
497 uint32_t protocol_version;
498 const uint8_t *inhdr = NULL;
499 uint16_t cmd;
500 uint32_t next_command_ofs;
501 NTSTATUS status;
502 NTTIME now;
504 if (size < (4 + SMB2_HDR_BODY + 2)) {
505 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
506 return NT_STATUS_INVALID_PARAMETER;
509 inhdr = inbuf + 4;
511 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
512 if (protocol_version != SMB2_MAGIC) {
513 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
514 protocol_version));
515 return NT_STATUS_INVALID_PARAMETER;
518 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
519 if (cmd != SMB2_OP_NEGPROT) {
520 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
521 cmd));
522 return NT_STATUS_INVALID_PARAMETER;
525 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
526 if (next_command_ofs != 0) {
527 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
528 next_command_ofs));
529 return NT_STATUS_INVALID_PARAMETER;
532 req = smbd_smb2_request_allocate(sconn);
533 if (req == NULL) {
534 return NT_STATUS_NO_MEMORY;
536 req->sconn = sconn;
538 talloc_steal(req, inbuf);
540 req->request_time = timeval_current();
541 now = timeval_to_nttime(&req->request_time);
543 status = smbd_smb2_inbuf_parse_compound(sconn->conn,
544 now,
545 inbuf + NBT_HDR_SIZE,
546 size - NBT_HDR_SIZE,
547 req, &req->in.vector,
548 &req->in.vector_count);
549 if (!NT_STATUS_IS_OK(status)) {
550 TALLOC_FREE(req);
551 return status;
554 req->current_idx = 1;
556 *_req = req;
557 return NT_STATUS_OK;
560 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
561 uint64_t message_id, uint64_t seq_id)
563 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
564 unsigned int offset;
566 if (seq_id < sconn->smb2.seqnum_low) {
567 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
568 "%llu (sequence id %llu) "
569 "(granted = %u, low = %llu, range = %u)\n",
570 (unsigned long long)message_id,
571 (unsigned long long)seq_id,
572 (unsigned int)sconn->smb2.credits_granted,
573 (unsigned long long)sconn->smb2.seqnum_low,
574 (unsigned int)sconn->smb2.seqnum_range));
575 return false;
578 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
579 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
580 "%llu (sequence id %llu) "
581 "(granted = %u, low = %llu, range = %u)\n",
582 (unsigned long long)message_id,
583 (unsigned long long)seq_id,
584 (unsigned int)sconn->smb2.credits_granted,
585 (unsigned long long)sconn->smb2.seqnum_low,
586 (unsigned int)sconn->smb2.seqnum_range));
587 return false;
590 offset = seq_id % sconn->smb2.max_credits;
592 if (bitmap_query(credits_bm, offset)) {
593 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
594 "%llu (sequence id %llu) "
595 "(granted = %u, low = %llu, range = %u) "
596 "(bm offset %u)\n",
597 (unsigned long long)message_id,
598 (unsigned long long)seq_id,
599 (unsigned int)sconn->smb2.credits_granted,
600 (unsigned long long)sconn->smb2.seqnum_low,
601 (unsigned int)sconn->smb2.seqnum_range,
602 offset));
603 return false;
606 /* Mark the message_ids as seen in the bitmap. */
607 bitmap_set(credits_bm, offset);
609 if (seq_id != sconn->smb2.seqnum_low) {
610 return true;
614 * Move the window forward by all the message_id's
615 * already seen.
617 while (bitmap_query(credits_bm, offset)) {
618 DEBUG(10,("smb2_validate_sequence_number: clearing "
619 "id %llu (position %u) from bitmap\n",
620 (unsigned long long)(sconn->smb2.seqnum_low),
621 offset));
622 bitmap_clear(credits_bm, offset);
624 sconn->smb2.seqnum_low += 1;
625 sconn->smb2.seqnum_range -= 1;
626 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
629 return true;
632 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
633 const uint8_t *inhdr)
635 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
636 uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
637 uint16_t credit_charge = 1;
638 uint64_t i;
640 if (opcode == SMB2_OP_CANCEL) {
641 /* SMB2_CANCEL requests by definition resend messageids. */
642 return true;
645 if (sconn->smb2.supports_multicredit) {
646 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
647 credit_charge = MAX(credit_charge, 1);
650 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
651 "credits_granted %llu, "
652 "seqnum low/range: %llu/%llu\n",
653 (unsigned long long) message_id,
654 (unsigned long long) credit_charge,
655 (unsigned long long) sconn->smb2.credits_granted,
656 (unsigned long long) sconn->smb2.seqnum_low,
657 (unsigned long long) sconn->smb2.seqnum_range));
659 if (sconn->smb2.credits_granted < credit_charge) {
660 DEBUG(0, ("smb2_validate_message_id: client used more "
661 "credits than granted, mid %llu, charge %llu, "
662 "credits_granted %llu, "
663 "seqnum low/range: %llu/%llu\n",
664 (unsigned long long) message_id,
665 (unsigned long long) credit_charge,
666 (unsigned long long) sconn->smb2.credits_granted,
667 (unsigned long long) sconn->smb2.seqnum_low,
668 (unsigned long long) sconn->smb2.seqnum_range));
669 return false;
673 * now check the message ids
675 * for multi-credit requests we need to check all current mid plus
676 * the implicit mids caused by the credit charge
677 * e.g. current mid = 15, charge 5 => mark 15-19 as used
680 for (i = 0; i <= (credit_charge-1); i++) {
681 uint64_t id = message_id + i;
682 bool ok;
684 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
685 (unsigned long long)message_id,
686 credit_charge,
687 (unsigned long long)id));
689 ok = smb2_validate_sequence_number(sconn, message_id, id);
690 if (!ok) {
691 return false;
695 /* substract used credits */
696 sconn->smb2.credits_granted -= credit_charge;
698 return true;
701 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
703 int count;
704 int idx;
706 count = req->in.vector_count;
708 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
709 /* It's not a SMB2 request */
710 return NT_STATUS_INVALID_PARAMETER;
713 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
714 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
715 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
716 const uint8_t *inhdr = NULL;
718 if (hdr->iov_len != SMB2_HDR_BODY) {
719 return NT_STATUS_INVALID_PARAMETER;
722 if (body->iov_len < 2) {
723 return NT_STATUS_INVALID_PARAMETER;
726 inhdr = (const uint8_t *)hdr->iov_base;
728 /* Check the SMB2 header */
729 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
730 return NT_STATUS_INVALID_PARAMETER;
733 if (!smb2_validate_message_id(req->sconn, inhdr)) {
734 return NT_STATUS_INVALID_PARAMETER;
738 return NT_STATUS_OK;
741 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
742 const struct iovec *in_vector,
743 struct iovec *out_vector)
745 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
746 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
747 uint16_t credit_charge = 1;
748 uint16_t credits_requested;
749 uint32_t out_flags;
750 uint16_t cmd;
751 NTSTATUS out_status;
752 uint16_t credits_granted = 0;
753 uint64_t credits_possible;
754 uint16_t current_max_credits;
757 * first we grant only 1/16th of the max range.
759 * Windows also starts with the 1/16th and then grants
760 * more later. I was only able to trigger higher
761 * values, when using a verify high credit charge.
763 * TODO: scale up depending one load, free memory
764 * or other stuff.
765 * Maybe also on the relationship between number
766 * of requests and the used sequence number.
767 * Which means we would grant more credits
768 * for client which use multi credit requests.
770 current_max_credits = sconn->smb2.max_credits / 16;
771 current_max_credits = MAX(current_max_credits, 1);
773 if (sconn->smb2.supports_multicredit) {
774 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
775 credit_charge = MAX(credit_charge, 1);
778 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
779 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
780 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
781 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
783 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
785 if (sconn->smb2.max_credits < credit_charge) {
786 smbd_server_connection_terminate(sconn,
787 "client error: credit charge > max credits\n");
788 return;
791 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
793 * In case we already send an async interim
794 * response, we should not grant
795 * credits on the final response.
797 credits_granted = 0;
798 } else if (credits_requested > 0) {
799 uint16_t additional_max = 0;
800 uint16_t additional_credits = credits_requested - 1;
802 switch (cmd) {
803 case SMB2_OP_NEGPROT:
804 break;
805 case SMB2_OP_SESSSETUP:
807 * Windows 2012 RC1 starts to grant
808 * additional credits
809 * with a successful session setup
811 if (NT_STATUS_IS_OK(out_status)) {
812 additional_max = 32;
814 break;
815 default:
817 * We match windows and only grant additional credits
818 * in chunks of 32.
820 additional_max = 32;
821 break;
824 additional_credits = MIN(additional_credits, additional_max);
826 credits_granted = credit_charge + additional_credits;
827 } else if (sconn->smb2.credits_granted == 0) {
829 * Make sure the client has always at least one credit
831 credits_granted = 1;
835 * sequence numbers should not wrap
837 * 1. calculate the possible credits until
838 * the sequence numbers start to wrap on 64-bit.
840 * 2. UINT64_MAX is used for Break Notifications.
842 * 2. truncate the possible credits to the maximum
843 * credits we want to grant to the client in total.
845 * 3. remove the range we'll already granted to the client
846 * this makes sure the client consumes the lowest sequence
847 * number, before we can grant additional credits.
849 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
850 if (credits_possible > 0) {
851 /* remove UINT64_MAX */
852 credits_possible -= 1;
854 credits_possible = MIN(credits_possible, current_max_credits);
855 credits_possible -= sconn->smb2.seqnum_range;
857 credits_granted = MIN(credits_granted, credits_possible);
859 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
860 sconn->smb2.credits_granted += credits_granted;
861 sconn->smb2.seqnum_range += credits_granted;
863 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
864 "granted %u, current possible/max %u/%u, "
865 "total granted/max/low/range %u/%u/%llu/%u\n",
866 (unsigned int)credits_requested,
867 (unsigned int)credit_charge,
868 (unsigned int)credits_granted,
869 (unsigned int)credits_possible,
870 (unsigned int)current_max_credits,
871 (unsigned int)sconn->smb2.credits_granted,
872 (unsigned int)sconn->smb2.max_credits,
873 (unsigned long long)sconn->smb2.seqnum_low,
874 (unsigned int)sconn->smb2.seqnum_range));
877 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
878 struct smbd_smb2_request *outreq)
880 int count, idx;
881 uint16_t total_credits = 0;
883 count = outreq->out.vector_count;
885 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
886 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
887 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
888 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
890 smb2_set_operation_credit(outreq->sconn, inhdr_v, outhdr_v);
892 /* To match Windows, count up what we
893 just granted. */
894 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
895 /* Set to zero in all but the last reply. */
896 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
897 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
898 } else {
899 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
904 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
906 struct iovec *vector;
907 int count;
908 int idx;
910 count = req->in.vector_count;
911 vector = talloc_zero_array(req, struct iovec, count);
912 if (vector == NULL) {
913 return NT_STATUS_NO_MEMORY;
916 vector[0].iov_base = req->out.nbt_hdr;
917 vector[0].iov_len = 4;
918 SIVAL(req->out.nbt_hdr, 0, 0);
920 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
921 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
922 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
923 uint8_t *outhdr = NULL;
924 uint8_t *outbody = NULL;
925 uint32_t next_command_ofs = 0;
926 struct iovec *current = &vector[idx];
928 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
929 /* we have a next command -
930 * setup for the error case. */
931 next_command_ofs = SMB2_HDR_BODY + 9;
934 outhdr = talloc_zero_array(vector, uint8_t,
935 OUTVEC_ALLOC_SIZE);
936 if (outhdr == NULL) {
937 return NT_STATUS_NO_MEMORY;
940 outbody = outhdr + SMB2_HDR_BODY;
943 * SMBD_SMB2_TF_IOV_OFS might be used later
945 current[SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
946 current[SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
948 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
949 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
951 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
952 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
954 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
955 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
957 /* setup the SMB2 header */
958 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
959 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
960 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
961 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
962 SIVAL(outhdr, SMB2_HDR_STATUS,
963 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
964 SSVAL(outhdr, SMB2_HDR_OPCODE,
965 SVAL(inhdr, SMB2_HDR_OPCODE));
966 SIVAL(outhdr, SMB2_HDR_FLAGS,
967 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
968 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
969 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
970 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
971 SIVAL(outhdr, SMB2_HDR_PID,
972 IVAL(inhdr, SMB2_HDR_PID));
973 SIVAL(outhdr, SMB2_HDR_TID,
974 IVAL(inhdr, SMB2_HDR_TID));
975 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
976 BVAL(inhdr, SMB2_HDR_SESSION_ID));
977 memcpy(outhdr + SMB2_HDR_SIGNATURE,
978 inhdr + SMB2_HDR_SIGNATURE, 16);
980 /* setup error body header */
981 SSVAL(outbody, 0x00, 0x08 + 1);
982 SSVAL(outbody, 0x02, 0);
983 SIVAL(outbody, 0x04, 0);
986 req->out.vector = vector;
987 req->out.vector_count = count;
989 /* setup the length of the NBT packet */
990 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
992 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
994 return NT_STATUS_OK;
997 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
998 const char *reason,
999 const char *location)
1001 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
1002 reason, location));
1003 exit_server_cleanly(reason);
1006 static bool dup_smb2_vec4(TALLOC_CTX *ctx,
1007 struct iovec *outvec,
1008 const struct iovec *srcvec)
1010 const uint8_t *srctf;
1011 size_t srctf_len;
1012 const uint8_t *srchdr;
1013 size_t srchdr_len;
1014 const uint8_t *srcbody;
1015 size_t srcbody_len;
1016 const uint8_t *expected_srcbody;
1017 const uint8_t *srcdyn;
1018 size_t srcdyn_len;
1019 const uint8_t *expected_srcdyn;
1020 uint8_t *dsttf;
1021 uint8_t *dsthdr;
1022 uint8_t *dstbody;
1023 uint8_t *dstdyn;
1025 srctf = (const uint8_t *)srcvec[SMBD_SMB2_TF_IOV_OFS].iov_base;
1026 srctf_len = srcvec[SMBD_SMB2_TF_IOV_OFS].iov_len;
1027 srchdr = (const uint8_t *)srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base;
1028 srchdr_len = srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_len;
1029 srcbody = (const uint8_t *)srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_base;
1030 srcbody_len = srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_len;
1031 expected_srcbody = srchdr + SMB2_HDR_BODY;
1032 srcdyn = (const uint8_t *)srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_base;
1033 srcdyn_len = srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_len;
1034 expected_srcdyn = srcbody + 8;
1036 if ((srctf_len != SMB2_TF_HDR_SIZE) && (srctf_len != 0)) {
1037 return false;
1040 if (srchdr_len != SMB2_HDR_BODY) {
1041 return false;
1044 if (srctf_len == SMB2_TF_HDR_SIZE) {
1045 dsttf = talloc_memdup(ctx, srctf, SMB2_TF_HDR_SIZE);
1046 if (dsttf == NULL) {
1047 return false;
1049 } else {
1050 dsttf = NULL;
1052 outvec[SMBD_SMB2_TF_IOV_OFS].iov_base = (void *)dsttf;
1053 outvec[SMBD_SMB2_TF_IOV_OFS].iov_len = srctf_len;
1055 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
1056 * be allocated with size OUTVEC_ALLOC_SIZE. */
1058 dsthdr = talloc_memdup(ctx, srchdr, OUTVEC_ALLOC_SIZE);
1059 if (dsthdr == NULL) {
1060 return false;
1062 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)dsthdr;
1063 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1066 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
1067 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
1068 * then duplicate this. Else use talloc_memdup().
1071 if ((srcbody == expected_srcbody) && (srcbody_len == 8)) {
1072 dstbody = dsthdr + SMB2_HDR_BODY;
1073 } else {
1074 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1075 if (dstbody == NULL) {
1076 return false;
1079 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)dstbody;
1080 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_len = srcbody_len;
1083 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1084 * pointing to
1085 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1086 * then duplicate this. Else use talloc_memdup().
1089 if ((srcdyn == expected_srcdyn) && (srcdyn_len == 1)) {
1090 dstdyn = dsthdr + SMB2_HDR_BODY + 8;
1091 } else if (srcdyn == NULL) {
1092 dstdyn = NULL;
1093 } else {
1094 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1095 if (dstdyn == NULL) {
1096 return false;
1099 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1100 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
1102 return true;
1105 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
1107 struct smbd_smb2_request *newreq = NULL;
1108 struct iovec *outvec = NULL;
1109 int count = req->out.vector_count;
1110 int i;
1112 newreq = smbd_smb2_request_allocate(req->sconn);
1113 if (!newreq) {
1114 return NULL;
1117 newreq->sconn = req->sconn;
1118 newreq->session = req->session;
1119 newreq->do_encryption = req->do_encryption;
1120 newreq->do_signing = req->do_signing;
1121 newreq->current_idx = req->current_idx;
1123 outvec = talloc_zero_array(newreq, struct iovec, count);
1124 if (!outvec) {
1125 TALLOC_FREE(newreq);
1126 return NULL;
1128 newreq->out.vector = outvec;
1129 newreq->out.vector_count = count;
1131 /* Setup the outvec's identically to req. */
1132 outvec[0].iov_base = newreq->out.nbt_hdr;
1133 outvec[0].iov_len = 4;
1134 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1136 /* Setup the vectors identically to the ones in req. */
1137 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1138 if (!dup_smb2_vec4(outvec, &outvec[i], &req->out.vector[i])) {
1139 break;
1143 if (i < count) {
1144 /* Alloc failed. */
1145 TALLOC_FREE(newreq);
1146 return NULL;
1149 smb2_setup_nbt_length(newreq->out.vector,
1150 newreq->out.vector_count);
1152 return newreq;
1155 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1157 struct smbd_server_connection *sconn = req->sconn;
1158 struct smbXsrv_connection *conn = req->sconn->conn;
1159 int first_idx = 1;
1160 struct iovec *firsttf = NULL;
1161 struct iovec *outhdr_v = NULL;
1162 uint8_t *outhdr = NULL;
1163 struct smbd_smb2_request *nreq = NULL;
1164 NTSTATUS status;
1166 /* Create a new smb2 request we'll use
1167 for the interim return. */
1168 nreq = dup_smb2_req(req);
1169 if (!nreq) {
1170 return NT_STATUS_NO_MEMORY;
1173 /* Lose the last X out vectors. They're the
1174 ones we'll be using for the async reply. */
1175 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1177 smb2_setup_nbt_length(nreq->out.vector,
1178 nreq->out.vector_count);
1180 /* Step back to the previous reply. */
1181 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1182 firsttf = SMBD_SMB2_IDX_TF_IOV(nreq,out,first_idx);
1183 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1184 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1185 /* And end the chain. */
1186 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1188 /* Calculate outgoing credits */
1189 smb2_calculate_credits(req, nreq);
1191 if (DEBUGLEVEL >= 10) {
1192 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1193 (unsigned int)nreq->current_idx );
1194 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1195 (unsigned int)nreq->out.vector_count );
1196 print_req_vectors(nreq);
1200 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1201 * we need to sign/encrypt here with the last/first key we remembered
1203 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
1204 status = smb2_signing_encrypt_pdu(req->first_key,
1205 conn->protocol,
1206 firsttf,
1207 nreq->out.vector_count - first_idx);
1208 if (!NT_STATUS_IS_OK(status)) {
1209 return status;
1211 } else if (req->last_key.length > 0) {
1212 status = smb2_signing_sign_pdu(req->last_key,
1213 conn->protocol,
1214 outhdr_v,
1215 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 return status;
1221 nreq->queue_entry.mem_ctx = nreq;
1222 nreq->queue_entry.vector = nreq->out.vector;
1223 nreq->queue_entry.count = nreq->out.vector_count;
1224 DLIST_ADD_END(nreq->sconn->smb2.send_queue, &nreq->queue_entry, NULL);
1225 nreq->sconn->smb2.send_queue_len++;
1227 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
1228 if (!NT_STATUS_IS_OK(status)) {
1229 return status;
1232 return NT_STATUS_OK;
1235 struct smbd_smb2_request_pending_state {
1236 struct smbd_server_connection *sconn;
1237 struct smbd_smb2_send_queue queue_entry;
1238 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x08 + 1];
1239 struct iovec vector[1 + SMBD_SMB2_NUM_IOV_PER_REQ];
1242 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1243 struct tevent_timer *te,
1244 struct timeval current_time,
1245 void *private_data);
1247 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1248 struct tevent_req *subreq,
1249 uint32_t defer_time)
1251 NTSTATUS status;
1252 struct timeval defer_endtime;
1253 uint8_t *outhdr = NULL;
1254 uint32_t flags;
1256 if (!tevent_req_is_in_progress(subreq)) {
1258 * This is a performance optimization,
1259 * it avoids one tevent_loop iteration,
1260 * which means we avoid one
1261 * talloc_stackframe_pool/talloc_free pair.
1263 tevent_req_notify_callback(subreq);
1264 return NT_STATUS_OK;
1267 req->subreq = subreq;
1268 subreq = NULL;
1270 if (req->async_te) {
1271 /* We're already async. */
1272 return NT_STATUS_OK;
1275 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1276 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1277 if (flags & SMB2_HDR_FLAG_ASYNC) {
1278 /* We're already async. */
1279 return NT_STATUS_OK;
1282 if (req->in.vector_count > req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1284 * We're trying to go async in a compound
1285 * request chain.
1286 * This is only allowed for opens that
1287 * cause an oplock break, otherwise it
1288 * is not allowed. See [MS-SMB2].pdf
1289 * note <194> on Section 3.3.5.2.7.
1291 const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1293 if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_CREATE) {
1295 * Cancel the outstanding request.
1297 bool ok = tevent_req_cancel(req->subreq);
1298 if (ok) {
1299 return NT_STATUS_OK;
1301 TALLOC_FREE(req->subreq);
1302 return smbd_smb2_request_error(req,
1303 NT_STATUS_INTERNAL_ERROR);
1307 if (DEBUGLEVEL >= 10) {
1308 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1309 (unsigned int)req->current_idx );
1310 print_req_vectors(req);
1313 if (req->current_idx > 1) {
1315 * We're going async in a compound
1316 * chain after the first request has
1317 * already been processed. Send an
1318 * interim response containing the
1319 * set of replies already generated.
1321 int idx = req->current_idx;
1323 status = smb2_send_async_interim_response(req);
1324 if (!NT_STATUS_IS_OK(status)) {
1325 return status;
1327 data_blob_clear_free(&req->first_key);
1329 req->current_idx = 1;
1332 * Re-arrange the in.vectors to remove what
1333 * we just sent.
1335 memmove(&req->in.vector[1],
1336 &req->in.vector[idx],
1337 sizeof(req->in.vector[0])*(req->in.vector_count - idx));
1338 req->in.vector_count = 1 + (req->in.vector_count - idx);
1340 /* Re-arrange the out.vectors to match. */
1341 memmove(&req->out.vector[1],
1342 &req->out.vector[idx],
1343 sizeof(req->out.vector[0])*(req->out.vector_count - idx));
1344 req->out.vector_count = 1 + (req->out.vector_count - idx);
1346 if (req->in.vector_count == 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
1348 * We only have one remaining request as
1349 * we've processed everything else.
1350 * This is no longer a compound request.
1352 req->compound_related = false;
1353 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1354 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1355 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1358 data_blob_clear_free(&req->last_key);
1360 defer_endtime = timeval_current_ofs_usec(defer_time);
1361 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1362 req, defer_endtime,
1363 smbd_smb2_request_pending_timer,
1364 req);
1365 if (req->async_te == NULL) {
1366 return NT_STATUS_NO_MEMORY;
1369 return NT_STATUS_OK;
1372 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1373 struct tevent_timer *te,
1374 struct timeval current_time,
1375 void *private_data)
1377 struct smbd_smb2_request *req =
1378 talloc_get_type_abort(private_data,
1379 struct smbd_smb2_request);
1380 struct smbd_server_connection *sconn = req->sconn;
1381 struct smbd_smb2_request_pending_state *state = NULL;
1382 uint8_t *outhdr = NULL;
1383 const uint8_t *inhdr = NULL;
1384 uint8_t *tf = NULL;
1385 size_t tf_len = 0;
1386 uint8_t *hdr = NULL;
1387 uint8_t *body = NULL;
1388 uint8_t *dyn = NULL;
1389 uint32_t flags = 0;
1390 uint64_t session_id = 0;
1391 uint64_t message_id = 0;
1392 uint64_t nonce_high = 0;
1393 uint64_t nonce_low = 0;
1394 uint64_t async_id = 0;
1395 NTSTATUS status;
1397 TALLOC_FREE(req->async_te);
1399 /* Ensure our final reply matches the interim one. */
1400 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1401 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1402 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1403 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1404 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1406 async_id = message_id; /* keep it simple for now... */
1408 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1409 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1411 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1412 "going async\n",
1413 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1414 (unsigned long long)async_id ));
1417 * What we send is identical to a smbd_smb2_request_error
1418 * packet with an error status of STATUS_PENDING. Make use
1419 * of this fact sometime when refactoring. JRA.
1422 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1423 if (state == NULL) {
1424 smbd_server_connection_terminate(req->sconn,
1425 nt_errstr(NT_STATUS_NO_MEMORY));
1426 return;
1428 state->sconn = req->sconn;
1430 tf = state->buf + NBT_HDR_SIZE;
1431 tf_len = SMB2_TF_HDR_SIZE;
1433 hdr = tf + SMB2_TF_HDR_SIZE;
1434 body = hdr + SMB2_HDR_BODY;
1435 dyn = body + 8;
1437 if (req->do_encryption) {
1438 struct smbXsrv_session *x = req->session;
1440 nonce_high = x->nonce_high;
1441 nonce_low = x->nonce_low;
1443 x->nonce_low += 1;
1444 if (x->nonce_low == 0) {
1445 x->nonce_low += 1;
1446 x->nonce_high += 1;
1450 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1451 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1452 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1453 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1455 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1456 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1457 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1458 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1459 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1461 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1462 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1463 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1464 SBVAL(hdr, SMB2_HDR_PID, async_id);
1465 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1466 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1467 memcpy(hdr+SMB2_HDR_SIGNATURE,
1468 outhdr+SMB2_HDR_SIGNATURE, 16);
1470 SSVAL(body, 0x00, 0x08 + 1);
1472 SCVAL(body, 0x02, 0);
1473 SCVAL(body, 0x03, 0);
1474 SIVAL(body, 0x04, 0);
1475 /* Match W2K8R2... */
1476 SCVAL(dyn, 0x00, 0x21);
1478 state->vector[0].iov_base = (void *)state->buf;
1479 state->vector[0].iov_len = NBT_HDR_SIZE;
1481 if (req->do_encryption) {
1482 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1483 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1484 } else {
1485 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1486 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1489 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1490 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1492 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1493 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1495 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1496 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1498 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1500 /* Ensure we correctly go through crediting. Grant
1501 the credits now, and zero credits on the final
1502 response. */
1503 smb2_set_operation_credit(req->sconn,
1504 SMBD_SMB2_IN_HDR_IOV(req),
1505 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1507 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1509 if (DEBUGLVL(10)) {
1510 int i;
1512 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1513 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1514 (unsigned int)i,
1515 (unsigned int)ARRAY_SIZE(state->vector),
1516 (unsigned int)state->vector[i].iov_len);
1520 if (req->do_encryption) {
1521 struct smbXsrv_session *x = req->session;
1522 struct smbXsrv_connection *conn = x->connection;
1523 DATA_BLOB encryption_key = x->global->encryption_key;
1525 status = smb2_signing_encrypt_pdu(encryption_key,
1526 conn->protocol,
1527 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1528 SMBD_SMB2_NUM_IOV_PER_REQ);
1529 if (!NT_STATUS_IS_OK(status)) {
1530 smbd_server_connection_terminate(req->sconn,
1531 nt_errstr(status));
1532 return;
1534 } else if (req->do_signing) {
1535 struct smbXsrv_session *x = req->session;
1536 struct smbXsrv_connection *conn = x->connection;
1537 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1539 status = smb2_signing_sign_pdu(signing_key,
1540 conn->protocol,
1541 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1542 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1543 if (!NT_STATUS_IS_OK(status)) {
1544 smbd_server_connection_terminate(req->sconn,
1545 nt_errstr(status));
1546 return;
1550 state->queue_entry.mem_ctx = state;
1551 state->queue_entry.vector = state->vector;
1552 state->queue_entry.count = ARRAY_SIZE(state->vector);
1553 DLIST_ADD_END(sconn->smb2.send_queue, &state->queue_entry, NULL);
1554 sconn->smb2.send_queue_len++;
1556 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
1557 if (!NT_STATUS_IS_OK(status)) {
1558 smbd_server_connection_terminate(sconn,
1559 nt_errstr(status));
1560 return;
1564 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1566 struct smbd_server_connection *sconn = req->sconn;
1567 struct smbd_smb2_request *cur;
1568 const uint8_t *inhdr;
1569 uint32_t flags;
1570 uint64_t search_message_id;
1571 uint64_t search_async_id;
1572 uint64_t found_id;
1574 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1576 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1577 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1578 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1581 * we don't need the request anymore
1582 * cancel requests never have a response
1584 DLIST_REMOVE(req->sconn->smb2.requests, req);
1585 TALLOC_FREE(req);
1587 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1588 const uint8_t *outhdr;
1589 uint64_t message_id;
1590 uint64_t async_id;
1592 if (cur->compound_related) {
1594 * Never cancel anything in a compound request.
1595 * Way too hard to deal with the result.
1597 continue;
1600 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1602 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1603 async_id = BVAL(outhdr, SMB2_HDR_PID);
1605 if (flags & SMB2_HDR_FLAG_ASYNC) {
1606 if (search_async_id == async_id) {
1607 found_id = async_id;
1608 break;
1610 } else {
1611 if (search_message_id == message_id) {
1612 found_id = message_id;
1613 break;
1618 if (cur && cur->subreq) {
1619 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1620 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1621 "cancel opcode[%s] mid %llu\n",
1622 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1623 (unsigned long long)found_id ));
1624 tevent_req_cancel(cur->subreq);
1627 return NT_STATUS_OK;
1630 /*************************************************************
1631 Ensure an incoming tid is a valid one for us to access.
1632 Change to the associated uid credentials and chdir to the
1633 valid tid directory.
1634 *************************************************************/
1636 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1638 const uint8_t *inhdr;
1639 uint32_t in_flags;
1640 uint32_t in_tid;
1641 struct smbXsrv_tcon *tcon;
1642 NTSTATUS status;
1643 NTTIME now = timeval_to_nttime(&req->request_time);
1645 req->tcon = NULL;
1647 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1649 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1650 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1652 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1653 in_tid = req->last_tid;
1656 req->last_tid = 0;
1658 status = smb2srv_tcon_lookup(req->session,
1659 in_tid, now, &tcon);
1660 if (!NT_STATUS_IS_OK(status)) {
1661 return status;
1664 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1665 return NT_STATUS_ACCESS_DENIED;
1668 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1669 if (!set_current_service(tcon->compat, 0, true)) {
1670 return NT_STATUS_ACCESS_DENIED;
1673 req->tcon = tcon;
1674 req->last_tid = in_tid;
1676 return NT_STATUS_OK;
1679 /*************************************************************
1680 Ensure an incoming session_id is a valid one for us to access.
1681 *************************************************************/
1683 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1685 const uint8_t *inhdr;
1686 uint32_t in_flags;
1687 uint16_t in_opcode;
1688 uint64_t in_session_id;
1689 struct smbXsrv_session *session = NULL;
1690 struct auth_session_info *session_info;
1691 NTSTATUS status;
1692 NTTIME now = timeval_to_nttime(&req->request_time);
1694 req->session = NULL;
1695 req->tcon = NULL;
1697 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1699 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1700 in_opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1701 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1703 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1704 in_session_id = req->last_session_id;
1707 req->last_session_id = 0;
1709 /* lookup an existing session */
1710 status = smb2srv_session_lookup(req->sconn->conn,
1711 in_session_id, now,
1712 &session);
1713 if (session) {
1714 req->session = session;
1715 req->last_session_id = in_session_id;
1717 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1718 switch (in_opcode) {
1719 case SMB2_OP_SESSSETUP:
1720 status = NT_STATUS_OK;
1721 break;
1722 default:
1723 break;
1726 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1727 switch (in_opcode) {
1728 case SMB2_OP_TCON:
1729 case SMB2_OP_CREATE:
1730 case SMB2_OP_GETINFO:
1731 case SMB2_OP_SETINFO:
1732 return NT_STATUS_INVALID_HANDLE;
1733 default:
1735 * Notice the check for
1736 * (session_info == NULL)
1737 * below.
1739 status = NT_STATUS_OK;
1740 break;
1743 if (!NT_STATUS_IS_OK(status)) {
1744 return status;
1747 session_info = session->global->auth_session_info;
1748 if (session_info == NULL) {
1749 return NT_STATUS_INVALID_HANDLE;
1752 if (in_session_id != req->sconn->conn->last_session_id) {
1753 req->sconn->conn->last_session_id = in_session_id;
1754 set_current_user_info(session_info->unix_info->sanitized_username,
1755 session_info->unix_info->unix_name,
1756 session_info->info->domain_name);
1759 return NT_STATUS_OK;
1762 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1763 uint32_t data_length)
1765 uint16_t needed_charge;
1766 uint16_t credit_charge = 1;
1767 const uint8_t *inhdr;
1769 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1771 if (req->sconn->smb2.supports_multicredit) {
1772 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1773 credit_charge = MAX(credit_charge, 1);
1776 needed_charge = (data_length - 1)/ 65536 + 1;
1778 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1779 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1780 credit_charge, needed_charge));
1782 if (needed_charge > credit_charge) {
1783 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1784 credit_charge, needed_charge));
1785 return NT_STATUS_INVALID_PARAMETER;
1788 return NT_STATUS_OK;
1791 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1792 size_t expected_body_size)
1794 struct iovec *inhdr_v;
1795 const uint8_t *inhdr;
1796 uint16_t opcode;
1797 const uint8_t *inbody;
1798 size_t body_size;
1799 size_t min_dyn_size = expected_body_size & 0x00000001;
1800 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1803 * The following should be checked already.
1805 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1806 return NT_STATUS_INTERNAL_ERROR;
1808 if (req->current_idx > max_idx) {
1809 return NT_STATUS_INTERNAL_ERROR;
1812 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1813 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1814 return NT_STATUS_INTERNAL_ERROR;
1816 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1817 return NT_STATUS_INTERNAL_ERROR;
1820 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1821 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1823 switch (opcode) {
1824 case SMB2_OP_IOCTL:
1825 case SMB2_OP_GETINFO:
1826 min_dyn_size = 0;
1827 break;
1831 * Now check the expected body size,
1832 * where the last byte might be in the
1833 * dynamic section..
1835 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1836 return NT_STATUS_INVALID_PARAMETER;
1838 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1839 return NT_STATUS_INVALID_PARAMETER;
1842 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1844 body_size = SVAL(inbody, 0x00);
1845 if (body_size != expected_body_size) {
1846 return NT_STATUS_INVALID_PARAMETER;
1849 return NT_STATUS_OK;
1852 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1854 struct smbXsrv_connection *conn = req->sconn->conn;
1855 const struct smbd_smb2_dispatch_table *call = NULL;
1856 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1857 const uint8_t *inhdr;
1858 uint16_t opcode;
1859 uint32_t flags;
1860 uint64_t mid;
1861 NTSTATUS status;
1862 NTSTATUS session_status;
1863 uint32_t allowed_flags;
1864 NTSTATUS return_value;
1865 struct smbXsrv_session *x = NULL;
1866 bool signing_required = false;
1867 bool encryption_required = false;
1869 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1871 /* TODO: verify more things */
1873 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1874 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1875 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1876 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1877 smb2_opcode_name(opcode),
1878 (unsigned long long)mid));
1880 if (conn->protocol >= PROTOCOL_SMB2_02) {
1882 * once the protocol is negotiated
1883 * SMB2_OP_NEGPROT is not allowed anymore
1885 if (opcode == SMB2_OP_NEGPROT) {
1886 /* drop the connection */
1887 return NT_STATUS_INVALID_PARAMETER;
1889 } else {
1891 * if the protocol is not negotiated yet
1892 * only SMB2_OP_NEGPROT is allowed.
1894 if (opcode != SMB2_OP_NEGPROT) {
1895 /* drop the connection */
1896 return NT_STATUS_INVALID_PARAMETER;
1901 * Check if the client provided a valid session id,
1902 * if so smbd_smb2_request_check_session() calls
1903 * set_current_user_info().
1905 * As some command don't require a valid session id
1906 * we defer the check of the session_status
1908 session_status = smbd_smb2_request_check_session(req);
1909 x = req->session;
1910 if (x != NULL) {
1911 signing_required = x->global->signing_required;
1912 encryption_required = x->global->encryption_required;
1914 if (opcode == SMB2_OP_SESSSETUP &&
1915 x->global->channels[0].signing_key.length) {
1916 signing_required = true;
1920 req->do_signing = false;
1921 req->do_encryption = false;
1922 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1923 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1924 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1926 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1927 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1928 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1929 (unsigned long long)x->global->session_wire_id,
1930 (unsigned long long)tf_session_id));
1932 * TODO: windows allows this...
1933 * should we drop the connection?
1935 * For now we just return ACCESS_DENIED
1936 * (Windows clients never trigger this)
1937 * and wait for an update of [MS-SMB2].
1939 return smbd_smb2_request_error(req,
1940 NT_STATUS_ACCESS_DENIED);
1943 req->do_encryption = true;
1946 if (encryption_required && !req->do_encryption) {
1947 return smbd_smb2_request_error(req,
1948 NT_STATUS_ACCESS_DENIED);
1951 call = smbd_smb2_call(opcode);
1952 if (call == NULL) {
1953 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1956 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1957 SMB2_HDR_FLAG_SIGNED |
1958 SMB2_HDR_FLAG_DFS;
1959 if (opcode == SMB2_OP_CANCEL) {
1960 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1962 if ((flags & ~allowed_flags) != 0) {
1963 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1966 if (flags & SMB2_HDR_FLAG_CHAINED) {
1968 * This check is mostly for giving the correct error code
1969 * for compounded requests.
1971 if (!NT_STATUS_IS_OK(session_status)) {
1972 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1974 } else {
1975 req->compat_chain_fsp = NULL;
1978 if (req->do_encryption) {
1979 signing_required = false;
1980 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1981 DATA_BLOB signing_key;
1983 if (x == NULL) {
1984 return smbd_smb2_request_error(
1985 req, NT_STATUS_ACCESS_DENIED);
1988 signing_key = x->global->channels[0].signing_key;
1991 * If we have a signing key, we should
1992 * sign the response
1994 if (signing_key.length > 0) {
1995 req->do_signing = true;
1998 status = smb2_signing_check_pdu(signing_key,
1999 conn->protocol,
2000 SMBD_SMB2_IN_HDR_IOV(req),
2001 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2002 if (!NT_STATUS_IS_OK(status)) {
2003 return smbd_smb2_request_error(req, status);
2007 * Now that we know the request was correctly signed
2008 * we have to sign the response too.
2010 req->do_signing = true;
2012 if (!NT_STATUS_IS_OK(session_status)) {
2013 return smbd_smb2_request_error(req, session_status);
2015 } else if (opcode == SMB2_OP_CANCEL) {
2016 /* Cancel requests are allowed to skip the signing */
2017 } else if (signing_required) {
2019 * If signing is required we try to sign
2020 * a possible error response
2022 req->do_signing = true;
2023 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2026 if (flags & SMB2_HDR_FLAG_CHAINED) {
2027 req->compound_related = true;
2030 if (call->need_session) {
2031 if (!NT_STATUS_IS_OK(session_status)) {
2032 return smbd_smb2_request_error(req, session_status);
2036 if (call->need_tcon) {
2037 SMB_ASSERT(call->need_session);
2040 * This call needs to be run as user.
2042 * smbd_smb2_request_check_tcon()
2043 * calls change_to_user() on success.
2045 status = smbd_smb2_request_check_tcon(req);
2046 if (!NT_STATUS_IS_OK(status)) {
2047 return smbd_smb2_request_error(req, status);
2049 if (req->tcon->global->encryption_required) {
2050 encryption_required = true;
2052 if (encryption_required && !req->do_encryption) {
2053 return smbd_smb2_request_error(req,
2054 NT_STATUS_ACCESS_DENIED);
2058 if (call->fileid_ofs != 0) {
2059 size_t needed = call->fileid_ofs + 16;
2060 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2061 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2062 uint64_t file_id_persistent;
2063 uint64_t file_id_volatile;
2064 struct files_struct *fsp;
2066 SMB_ASSERT(call->need_tcon);
2068 if (needed > body_size) {
2069 return smbd_smb2_request_error(req,
2070 NT_STATUS_INVALID_PARAMETER);
2073 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2074 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2076 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2077 if (fsp == NULL) {
2078 if (!call->allow_invalid_fileid) {
2079 return smbd_smb2_request_error(req,
2080 NT_STATUS_FILE_CLOSED);
2083 if (file_id_persistent != UINT64_MAX) {
2084 return smbd_smb2_request_error(req,
2085 NT_STATUS_FILE_CLOSED);
2087 if (file_id_volatile != UINT64_MAX) {
2088 return smbd_smb2_request_error(req,
2089 NT_STATUS_FILE_CLOSED);
2094 if (call->as_root) {
2095 SMB_ASSERT(call->fileid_ofs == 0);
2096 /* This call needs to be run as root */
2097 change_to_root_user();
2098 } else {
2099 SMB_ASSERT(call->need_tcon);
2102 switch (opcode) {
2103 case SMB2_OP_NEGPROT:
2105 START_PROFILE(smb2_negprot);
2106 return_value = smbd_smb2_request_process_negprot(req);
2107 END_PROFILE(smb2_negprot);
2109 break;
2111 case SMB2_OP_SESSSETUP:
2113 START_PROFILE(smb2_sesssetup);
2114 return_value = smbd_smb2_request_process_sesssetup(req);
2115 END_PROFILE(smb2_sesssetup);
2117 break;
2119 case SMB2_OP_LOGOFF:
2121 START_PROFILE(smb2_logoff);
2122 return_value = smbd_smb2_request_process_logoff(req);
2123 END_PROFILE(smb2_logoff);
2125 break;
2127 case SMB2_OP_TCON:
2129 START_PROFILE(smb2_tcon);
2130 return_value = smbd_smb2_request_process_tcon(req);
2131 END_PROFILE(smb2_tcon);
2133 break;
2135 case SMB2_OP_TDIS:
2137 START_PROFILE(smb2_tdis);
2138 return_value = smbd_smb2_request_process_tdis(req);
2139 END_PROFILE(smb2_tdis);
2141 break;
2143 case SMB2_OP_CREATE:
2145 START_PROFILE(smb2_create);
2146 return_value = smbd_smb2_request_process_create(req);
2147 END_PROFILE(smb2_create);
2149 break;
2151 case SMB2_OP_CLOSE:
2153 START_PROFILE(smb2_close);
2154 return_value = smbd_smb2_request_process_close(req);
2155 END_PROFILE(smb2_close);
2157 break;
2159 case SMB2_OP_FLUSH:
2161 START_PROFILE(smb2_flush);
2162 return_value = smbd_smb2_request_process_flush(req);
2163 END_PROFILE(smb2_flush);
2165 break;
2167 case SMB2_OP_READ:
2169 START_PROFILE(smb2_read);
2170 return_value = smbd_smb2_request_process_read(req);
2171 END_PROFILE(smb2_read);
2173 break;
2175 case SMB2_OP_WRITE:
2177 START_PROFILE(smb2_write);
2178 return_value = smbd_smb2_request_process_write(req);
2179 END_PROFILE(smb2_write);
2181 break;
2183 case SMB2_OP_LOCK:
2185 START_PROFILE(smb2_lock);
2186 return_value = smbd_smb2_request_process_lock(req);
2187 END_PROFILE(smb2_lock);
2189 break;
2191 case SMB2_OP_IOCTL:
2193 START_PROFILE(smb2_ioctl);
2194 return_value = smbd_smb2_request_process_ioctl(req);
2195 END_PROFILE(smb2_ioctl);
2197 break;
2199 case SMB2_OP_CANCEL:
2201 START_PROFILE(smb2_cancel);
2202 return_value = smbd_smb2_request_process_cancel(req);
2203 END_PROFILE(smb2_cancel);
2205 break;
2207 case SMB2_OP_KEEPALIVE:
2209 START_PROFILE(smb2_keepalive);
2210 return_value = smbd_smb2_request_process_keepalive(req);
2211 END_PROFILE(smb2_keepalive);
2213 break;
2215 case SMB2_OP_FIND:
2217 START_PROFILE(smb2_find);
2218 return_value = smbd_smb2_request_process_find(req);
2219 END_PROFILE(smb2_find);
2221 break;
2223 case SMB2_OP_NOTIFY:
2225 START_PROFILE(smb2_notify);
2226 return_value = smbd_smb2_request_process_notify(req);
2227 END_PROFILE(smb2_notify);
2229 break;
2231 case SMB2_OP_GETINFO:
2233 START_PROFILE(smb2_getinfo);
2234 return_value = smbd_smb2_request_process_getinfo(req);
2235 END_PROFILE(smb2_getinfo);
2237 break;
2239 case SMB2_OP_SETINFO:
2241 START_PROFILE(smb2_setinfo);
2242 return_value = smbd_smb2_request_process_setinfo(req);
2243 END_PROFILE(smb2_setinfo);
2245 break;
2247 case SMB2_OP_BREAK:
2249 START_PROFILE(smb2_break);
2250 return_value = smbd_smb2_request_process_break(req);
2251 END_PROFILE(smb2_break);
2253 break;
2255 default:
2256 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2257 break;
2259 return return_value;
2262 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2264 struct smbd_server_connection *sconn = req->sconn;
2265 struct smbXsrv_connection *conn = req->sconn->conn;
2266 int first_idx = 1;
2267 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2268 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2269 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2270 NTSTATUS status;
2272 req->subreq = NULL;
2273 TALLOC_FREE(req->async_te);
2275 if (req->do_encryption &&
2276 (firsttf->iov_len == 0) &&
2277 (req->first_key.length == 0) &&
2278 (req->session != NULL) &&
2279 (req->session->global->encryption_key.length != 0))
2281 DATA_BLOB encryption_key = req->session->global->encryption_key;
2282 uint8_t *tf;
2283 uint64_t session_id = req->session->global->session_wire_id;
2284 struct smbXsrv_session *x = req->session;
2285 uint64_t nonce_high;
2286 uint64_t nonce_low;
2288 nonce_high = x->nonce_high;
2289 nonce_low = x->nonce_low;
2291 x->nonce_low += 1;
2292 if (x->nonce_low == 0) {
2293 x->nonce_low += 1;
2294 x->nonce_high += 1;
2298 * We need to place the SMB2_TRANSFORM header before the
2299 * first SMB2 header
2303 * we need to remember the encryption key
2304 * and defer the signing/encryption until
2305 * we are sure that we do not change
2306 * the header again.
2308 req->first_key = data_blob_dup_talloc(req, encryption_key);
2309 if (req->first_key.data == NULL) {
2310 return NT_STATUS_NO_MEMORY;
2313 tf = talloc_zero_array(req->out.vector, uint8_t,
2314 SMB2_TF_HDR_SIZE);
2315 if (tf == NULL) {
2316 return NT_STATUS_NO_MEMORY;
2319 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2320 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2321 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2322 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2324 firsttf->iov_base = (void *)tf;
2325 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2328 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2329 (req->last_key.length > 0) &&
2330 (firsttf->iov_len == 0))
2332 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2333 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2336 * As we are sure the header of the last request in the
2337 * compound chain will not change, we can to sign here
2338 * with the last signing key we remembered.
2340 status = smb2_signing_sign_pdu(req->last_key,
2341 conn->protocol,
2342 lasthdr,
2343 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2344 if (!NT_STATUS_IS_OK(status)) {
2345 return status;
2348 data_blob_clear_free(&req->last_key);
2350 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2352 if (req->current_idx < req->out.vector_count) {
2354 * We must process the remaining compound
2355 * SMB2 requests before any new incoming SMB2
2356 * requests. This is because incoming SMB2
2357 * requests may include a cancel for a
2358 * compound request we haven't processed
2359 * yet.
2361 struct tevent_immediate *im = tevent_create_immediate(req);
2362 if (!im) {
2363 return NT_STATUS_NO_MEMORY;
2366 if (req->do_signing && firsttf->iov_len == 0) {
2367 struct smbXsrv_session *x = req->session;
2368 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2371 * we need to remember the signing key
2372 * and defer the signing until
2373 * we are sure that we do not change
2374 * the header again.
2376 req->last_key = data_blob_dup_talloc(req, signing_key);
2377 if (req->last_key.data == NULL) {
2378 return NT_STATUS_NO_MEMORY;
2382 tevent_schedule_immediate(im,
2383 req->sconn->ev_ctx,
2384 smbd_smb2_request_dispatch_immediate,
2385 req);
2386 return NT_STATUS_OK;
2389 if (req->compound_related) {
2390 req->compound_related = false;
2393 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2395 /* Set credit for these operations (zero credits if this
2396 is a final reply for an async operation). */
2397 smb2_calculate_credits(req, req);
2400 * now check if we need to sign the current response
2402 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2403 status = smb2_signing_encrypt_pdu(req->first_key,
2404 conn->protocol,
2405 firsttf,
2406 req->out.vector_count - first_idx);
2407 if (!NT_STATUS_IS_OK(status)) {
2408 return status;
2410 } else if (req->do_signing) {
2411 struct smbXsrv_session *x = req->session;
2412 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2414 status = smb2_signing_sign_pdu(signing_key,
2415 conn->protocol,
2416 outhdr,
2417 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2418 if (!NT_STATUS_IS_OK(status)) {
2419 return status;
2422 data_blob_clear_free(&req->first_key);
2424 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2425 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2426 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2427 /* Dynamic part is NULL. Chop it off,
2428 We're going to send it via sendfile. */
2429 req->out.vector_count -= 1;
2433 * We're done with this request -
2434 * move it off the "being processed" queue.
2436 DLIST_REMOVE(req->sconn->smb2.requests, req);
2438 req->queue_entry.mem_ctx = req;
2439 req->queue_entry.vector = req->out.vector;
2440 req->queue_entry.count = req->out.vector_count;
2441 DLIST_ADD_END(req->sconn->smb2.send_queue, &req->queue_entry, NULL);
2442 req->sconn->smb2.send_queue_len++;
2444 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2445 if (!NT_STATUS_IS_OK(status)) {
2446 return status;
2449 return NT_STATUS_OK;
2452 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2454 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2455 struct tevent_immediate *im,
2456 void *private_data)
2458 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2459 struct smbd_smb2_request);
2460 struct smbd_server_connection *sconn = req->sconn;
2461 NTSTATUS status;
2463 TALLOC_FREE(im);
2465 if (DEBUGLEVEL >= 10) {
2466 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2467 req->current_idx, req->in.vector_count));
2468 print_req_vectors(req);
2471 status = smbd_smb2_request_dispatch(req);
2472 if (!NT_STATUS_IS_OK(status)) {
2473 smbd_server_connection_terminate(sconn, nt_errstr(status));
2474 return;
2477 status = smbd_smb2_request_next_incoming(sconn);
2478 if (!NT_STATUS_IS_OK(status)) {
2479 smbd_server_connection_terminate(sconn, nt_errstr(status));
2480 return;
2484 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2485 NTSTATUS status,
2486 DATA_BLOB body, DATA_BLOB *dyn,
2487 const char *location)
2489 uint8_t *outhdr;
2490 struct iovec *outbody_v;
2491 struct iovec *outdyn_v;
2492 uint32_t next_command_ofs;
2494 DEBUG(10,("smbd_smb2_request_done_ex: "
2495 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2496 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2497 dyn ? "yes": "no",
2498 (unsigned int)(dyn ? dyn->length : 0),
2499 location));
2501 if (body.length < 2) {
2502 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2505 if ((body.length % 2) != 0) {
2506 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2509 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2510 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2511 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2513 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2514 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2516 outbody_v->iov_base = (void *)body.data;
2517 outbody_v->iov_len = body.length;
2519 if (dyn) {
2520 outdyn_v->iov_base = (void *)dyn->data;
2521 outdyn_v->iov_len = dyn->length;
2522 } else {
2523 outdyn_v->iov_base = NULL;
2524 outdyn_v->iov_len = 0;
2527 /* see if we need to recalculate the offset to the next response */
2528 if (next_command_ofs > 0) {
2529 next_command_ofs = SMB2_HDR_BODY;
2530 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2531 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2534 if ((next_command_ofs % 8) != 0) {
2535 size_t pad_size = 8 - (next_command_ofs % 8);
2536 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2538 * if the dyn buffer is empty
2539 * we can use it to add padding
2541 uint8_t *pad;
2543 pad = talloc_zero_array(req->out.vector,
2544 uint8_t, pad_size);
2545 if (pad == NULL) {
2546 return smbd_smb2_request_error(req,
2547 NT_STATUS_NO_MEMORY);
2550 outdyn_v->iov_base = (void *)pad;
2551 outdyn_v->iov_len = pad_size;
2552 } else {
2554 * For now we copy the dynamic buffer
2555 * and add the padding to the new buffer
2557 size_t old_size;
2558 uint8_t *old_dyn;
2559 size_t new_size;
2560 uint8_t *new_dyn;
2562 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2563 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2565 new_size = old_size + pad_size;
2566 new_dyn = talloc_zero_array(req->out.vector,
2567 uint8_t, new_size);
2568 if (new_dyn == NULL) {
2569 return smbd_smb2_request_error(req,
2570 NT_STATUS_NO_MEMORY);
2573 memcpy(new_dyn, old_dyn, old_size);
2574 memset(new_dyn + old_size, 0, pad_size);
2576 outdyn_v->iov_base = (void *)new_dyn;
2577 outdyn_v->iov_len = new_size;
2579 next_command_ofs += pad_size;
2582 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2584 return smbd_smb2_request_reply(req);
2587 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2588 NTSTATUS status,
2589 DATA_BLOB *info,
2590 const char *location)
2592 DATA_BLOB body;
2593 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2594 size_t unread_bytes = smbd_smb2_unread_bytes(req);
2596 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2597 req->current_idx, nt_errstr(status), info ? " +info" : "",
2598 location));
2600 if (unread_bytes) {
2601 /* Recvfile error. Drain incoming socket. */
2602 size_t ret;
2604 errno = 0;
2605 ret = drain_socket(req->sconn->sock, unread_bytes);
2606 if (ret != unread_bytes) {
2607 NTSTATUS error;
2609 if (errno == 0) {
2610 error = NT_STATUS_IO_DEVICE_ERROR;
2611 } else {
2612 error = map_nt_error_from_unix_common(errno);
2615 DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: "
2616 "ret[%u] errno[%d] => %s\n",
2617 (unsigned)unread_bytes,
2618 (unsigned)ret, errno, nt_errstr(error)));
2619 return error;
2623 body.data = outhdr + SMB2_HDR_BODY;
2624 body.length = 8;
2625 SSVAL(body.data, 0, 9);
2627 if (info) {
2628 SIVAL(body.data, 0x04, info->length);
2629 } else {
2630 /* Allocated size of req->out.vector[i].iov_base
2631 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2632 * 1 byte without having to do an alloc.
2634 info = talloc_zero_array(req->out.vector,
2635 DATA_BLOB,
2637 if (!info) {
2638 return NT_STATUS_NO_MEMORY;
2640 info->data = ((uint8_t *)outhdr) +
2641 OUTVEC_ALLOC_SIZE - 1;
2642 info->length = 1;
2643 SCVAL(info->data, 0, 0);
2647 * Note: Even if there is an error, continue to process the request.
2648 * per MS-SMB2.
2651 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2655 struct smbd_smb2_send_oplock_break_state {
2656 struct smbd_server_connection *sconn;
2657 struct smbd_smb2_send_queue queue_entry;
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 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2663 struct smbXsrv_session *session,
2664 struct smbXsrv_tcon *tcon,
2665 struct smbXsrv_open *op,
2666 uint8_t oplock_level)
2668 struct smbd_smb2_send_oplock_break_state *state;
2669 struct smbXsrv_connection *conn = sconn->conn;
2670 uint8_t *tf;
2671 size_t tf_len;
2672 uint8_t *hdr;
2673 uint8_t *body;
2674 size_t body_len;
2675 uint8_t *dyn;
2676 size_t dyn_len;
2677 bool do_encryption = session->global->encryption_required;
2678 uint64_t nonce_high = 0;
2679 uint64_t nonce_low = 0;
2680 NTSTATUS status;
2682 if (tcon->global->encryption_required) {
2683 do_encryption = true;
2686 state = talloc_zero(sconn, struct smbd_smb2_send_oplock_break_state);
2687 if (state == NULL) {
2688 return NT_STATUS_NO_MEMORY;
2690 state->sconn = sconn;
2692 tf = state->buf + NBT_HDR_SIZE;
2693 tf_len = SMB2_TF_HDR_SIZE;
2694 hdr = tf + tf_len;
2695 body = hdr + SMB2_HDR_BODY;
2696 body_len = 0x18;
2697 dyn = body + body_len;
2698 dyn_len = 0;
2700 if (do_encryption) {
2701 nonce_high = session->nonce_high;
2702 nonce_low = session->nonce_low;
2704 session->nonce_low += 1;
2705 if (session->nonce_low == 0) {
2706 session->nonce_low += 1;
2707 session->nonce_high += 1;
2711 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2712 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2713 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2714 SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
2716 SIVAL(hdr, 0, SMB2_MAGIC);
2717 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2718 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2719 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2720 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2721 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2722 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2723 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2724 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2725 SIVAL(hdr, SMB2_HDR_PID, 0);
2726 SIVAL(hdr, SMB2_HDR_TID, 0);
2727 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2728 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2730 SSVAL(body, 0x00, body_len);
2732 SCVAL(body, 0x02, oplock_level);
2733 SCVAL(body, 0x03, 0); /* reserved */
2734 SIVAL(body, 0x04, 0); /* reserved */
2735 SBVAL(body, 0x08, op->global->open_persistent_id);
2736 SBVAL(body, 0x10, op->global->open_volatile_id);
2738 state->vector[0].iov_base = (void *)state->buf;
2739 state->vector[0].iov_len = NBT_HDR_SIZE;
2741 if (do_encryption) {
2742 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
2743 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
2744 } else {
2745 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
2746 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
2749 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
2750 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
2752 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
2753 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = body_len;
2755 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
2756 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_len;
2758 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2760 if (do_encryption) {
2761 DATA_BLOB encryption_key = session->global->encryption_key;
2763 status = smb2_signing_encrypt_pdu(encryption_key,
2764 conn->protocol,
2765 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2766 SMBD_SMB2_NUM_IOV_PER_REQ);
2767 if (!NT_STATUS_IS_OK(status)) {
2768 return status;
2772 state->queue_entry.mem_ctx = state;
2773 state->queue_entry.vector = state->vector;
2774 state->queue_entry.count = ARRAY_SIZE(state->vector);
2775 DLIST_ADD_END(state->sconn->smb2.send_queue, &state->queue_entry, NULL);
2776 state->sconn->smb2.send_queue_len++;
2778 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2779 if (!NT_STATUS_IS_OK(status)) {
2780 return status;
2783 return NT_STATUS_OK;
2786 static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
2788 if (smb2_req->do_signing) {
2789 return 0;
2791 if (smb2_req->do_encryption) {
2792 return 0;
2794 return (size_t)lp_min_receive_file_size();
2797 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
2799 uint32_t flags;
2801 if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
2802 /* Transform header. Cannot recvfile. */
2803 return false;
2805 if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
2806 /* Not SMB2. Normal error path will cope. */
2807 return false;
2809 if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
2810 /* Not SMB2. Normal error path will cope. */
2811 return false;
2813 if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
2814 /* Needs to be a WRITE. */
2815 return false;
2817 if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
2818 /* Chained. Cannot recvfile. */
2819 return false;
2821 flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
2822 if (flags & SMB2_HDR_FLAG_CHAINED) {
2823 /* Chained. Cannot recvfile. */
2824 return false;
2826 if (flags & SMB2_HDR_FLAG_SIGNED) {
2827 /* Signed. Cannot recvfile. */
2828 return false;
2831 DEBUG(10,("Doing recvfile write len = %u\n",
2832 (unsigned int)(state->pktlen -
2833 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
2835 return true;
2838 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2840 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
2841 size_t max_send_queue_len;
2842 size_t cur_send_queue_len;
2844 if (!NT_STATUS_IS_OK(sconn->status)) {
2846 * we're not supposed to do any io
2848 return NT_STATUS_OK;
2851 if (state->req != NULL) {
2853 * if there is already a tstream_readv_pdu
2854 * pending, we are done.
2856 return NT_STATUS_OK;
2859 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2860 cur_send_queue_len = sconn->smb2.send_queue_len;
2862 if (cur_send_queue_len > max_send_queue_len) {
2864 * if we have a lot of requests to send,
2865 * we wait until they are on the wire until we
2866 * ask for the next request.
2868 return NT_STATUS_OK;
2871 /* ask for the next request */
2872 ZERO_STRUCTP(state);
2873 state->req = smbd_smb2_request_allocate(sconn);
2874 if (state->req == NULL) {
2875 return NT_STATUS_NO_MEMORY;
2877 state->req->sconn = sconn;
2878 state->min_recv_size = get_min_receive_file_size(state->req);
2880 TEVENT_FD_READABLE(sconn->smb2.fde);
2882 return NT_STATUS_OK;
2885 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2886 uint8_t *inbuf, size_t size)
2888 NTSTATUS status;
2889 struct smbd_smb2_request *req = NULL;
2891 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2892 (unsigned int)size));
2894 status = smbd_initialize_smb2(sconn);
2895 if (!NT_STATUS_IS_OK(status)) {
2896 smbd_server_connection_terminate(sconn, nt_errstr(status));
2897 return;
2900 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2901 if (!NT_STATUS_IS_OK(status)) {
2902 smbd_server_connection_terminate(sconn, nt_errstr(status));
2903 return;
2906 status = smbd_smb2_request_validate(req);
2907 if (!NT_STATUS_IS_OK(status)) {
2908 smbd_server_connection_terminate(sconn, nt_errstr(status));
2909 return;
2912 status = smbd_smb2_request_setup_out(req);
2913 if (!NT_STATUS_IS_OK(status)) {
2914 smbd_server_connection_terminate(sconn, nt_errstr(status));
2915 return;
2918 status = smbd_smb2_request_dispatch(req);
2919 if (!NT_STATUS_IS_OK(status)) {
2920 smbd_server_connection_terminate(sconn, nt_errstr(status));
2921 return;
2924 status = smbd_smb2_request_next_incoming(sconn);
2925 if (!NT_STATUS_IS_OK(status)) {
2926 smbd_server_connection_terminate(sconn, nt_errstr(status));
2927 return;
2930 sconn->num_requests++;
2933 static int socket_error_from_errno(int ret,
2934 int sys_errno,
2935 bool *retry)
2937 *retry = false;
2939 if (ret >= 0) {
2940 return 0;
2943 if (ret != -1) {
2944 return EIO;
2947 if (sys_errno == 0) {
2948 return EIO;
2951 if (sys_errno == EINTR) {
2952 *retry = true;
2953 return sys_errno;
2956 if (sys_errno == EINPROGRESS) {
2957 *retry = true;
2958 return sys_errno;
2961 if (sys_errno == EAGAIN) {
2962 *retry = true;
2963 return sys_errno;
2966 /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
2967 if (sys_errno == ENOMEM) {
2968 *retry = true;
2969 return sys_errno;
2972 #ifdef EWOULDBLOCK
2973 if (sys_errno == EWOULDBLOCK) {
2974 *retry = true;
2975 return sys_errno;
2977 #endif
2979 return sys_errno;
2982 static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn)
2984 int ret;
2985 int err;
2986 bool retry;
2988 if (sconn->smb2.send_queue == NULL) {
2989 TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
2990 return NT_STATUS_OK;
2993 while (sconn->smb2.send_queue != NULL) {
2994 struct smbd_smb2_send_queue *e = sconn->smb2.send_queue;
2996 if (e->sendfile_header != NULL) {
2997 size_t size = 0;
2998 size_t i = 0;
2999 uint8_t *buf;
3001 for (i=0; i < e->count; i++) {
3002 size += e->vector[i].iov_len;
3005 buf = talloc_array(e->mem_ctx, uint8_t, size);
3006 if (buf == NULL) {
3007 return NT_STATUS_NO_MEMORY;
3010 size = 0;
3011 for (i=0; i < e->count; i++) {
3012 memcpy(buf+size,
3013 e->vector[i].iov_base,
3014 e->vector[i].iov_len);
3015 size += e->vector[i].iov_len;
3018 e->sendfile_header->data = buf;
3019 e->sendfile_header->length = size;
3020 e->count = 0;
3022 sconn->smb2.send_queue_len--;
3023 DLIST_REMOVE(sconn->smb2.send_queue, e);
3024 talloc_free(e->mem_ctx);
3025 continue;
3028 ret = writev(sconn->sock, e->vector, e->count);
3029 if (ret == 0) {
3030 /* propagate end of file */
3031 return NT_STATUS_INTERNAL_ERROR;
3033 err = socket_error_from_errno(ret, errno, &retry);
3034 if (retry) {
3035 /* retry later */
3036 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
3037 return NT_STATUS_OK;
3039 if (err != 0) {
3040 return map_nt_error_from_unix_common(err);
3042 while (ret > 0) {
3043 if (ret < e->vector[0].iov_len) {
3044 uint8_t *base;
3045 base = (uint8_t *)e->vector[0].iov_base;
3046 base += ret;
3047 e->vector[0].iov_base = (void *)base;
3048 e->vector[0].iov_len -= ret;
3049 break;
3051 ret -= e->vector[0].iov_len;
3052 e->vector += 1;
3053 e->count -= 1;
3057 * there're maybe some empty vectors at the end
3058 * which we need to skip, otherwise we would get
3059 * ret == 0 from the readv() call and return EPIPE
3061 while (e->count > 0) {
3062 if (e->vector[0].iov_len > 0) {
3063 break;
3065 e->vector += 1;
3066 e->count -= 1;
3069 if (e->count > 0) {
3070 /* we have more to write */
3071 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
3072 return NT_STATUS_OK;
3075 sconn->smb2.send_queue_len--;
3076 DLIST_REMOVE(sconn->smb2.send_queue, e);
3077 talloc_free(e->mem_ctx);
3080 return NT_STATUS_OK;
3083 static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn,
3084 uint16_t fde_flags)
3086 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
3087 struct smbd_smb2_request *req = NULL;
3088 size_t min_recvfile_size = UINT32_MAX;
3089 int ret;
3090 int err;
3091 bool retry;
3092 NTSTATUS status;
3093 NTTIME now;
3095 if (!NT_STATUS_IS_OK(sconn->status)) {
3097 * we're not supposed to do any io
3099 TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
3100 TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
3101 return NT_STATUS_OK;
3104 if (fde_flags & TEVENT_FD_WRITE) {
3105 status = smbd_smb2_flush_send_queue(sconn);
3106 if (!NT_STATUS_IS_OK(status)) {
3107 return status;
3111 if (!(fde_flags & TEVENT_FD_READ)) {
3112 return NT_STATUS_OK;
3115 if (state->req == NULL) {
3116 TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
3117 return NT_STATUS_OK;
3120 again:
3121 if (!state->hdr.done) {
3122 state->hdr.done = true;
3124 state->vector.iov_base = (void *)state->hdr.nbt;
3125 state->vector.iov_len = NBT_HDR_SIZE;
3128 ret = readv(sconn->sock, &state->vector, 1);
3129 if (ret == 0) {
3130 /* propagate end of file */
3131 return NT_STATUS_END_OF_FILE;
3133 err = socket_error_from_errno(ret, errno, &retry);
3134 if (retry) {
3135 /* retry later */
3136 TEVENT_FD_READABLE(sconn->smb2.fde);
3137 return NT_STATUS_OK;
3139 if (err != 0) {
3140 return map_nt_error_from_unix_common(err);
3143 if (ret < state->vector.iov_len) {
3144 uint8_t *base;
3145 base = (uint8_t *)state->vector.iov_base;
3146 base += ret;
3147 state->vector.iov_base = (void *)base;
3148 state->vector.iov_len -= ret;
3149 /* we have more to read */
3150 TEVENT_FD_READABLE(sconn->smb2.fde);
3151 return NT_STATUS_OK;
3154 if (state->pktlen > 0) {
3155 if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
3157 * Not a possible receivefile write.
3158 * Read the rest of the data.
3160 state->doing_receivefile = false;
3161 state->vector.iov_base = (void *)(state->pktbuf +
3162 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3163 state->vector.iov_len = (state->pktlen -
3164 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3165 goto again;
3169 * Either this is a receivefile write so we've
3170 * done a short read, or if not we have all the data.
3172 goto got_full;
3176 * Now we analyze the NBT header
3178 state->pktlen = smb2_len(state->hdr.nbt);
3179 if (state->pktlen == 0) {
3180 goto got_full;
3183 state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
3184 if (state->pktbuf == NULL) {
3185 return NT_STATUS_NO_MEMORY;
3188 state->vector.iov_base = (void *)state->pktbuf;
3190 if (state->min_recv_size != 0) {
3191 min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3192 min_recvfile_size += state->min_recv_size;
3195 if (state->pktlen > min_recvfile_size) {
3197 * Might be a receivefile write. Read the SMB2 HEADER +
3198 * SMB2_WRITE header first. Set 'doing_receivefile'
3199 * as we're *attempting* receivefile write. If this
3200 * turns out not to be a SMB2_WRITE request or otherwise
3201 * not suitable then we'll just read the rest of the data
3202 * the next time this function is called.
3204 state->vector.iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3205 state->doing_receivefile = true;
3206 } else {
3207 state->vector.iov_len = state->pktlen;
3210 goto again;
3212 got_full:
3214 if (state->hdr.nbt[0] != 0x00) {
3215 DEBUG(1,("ignore NBT[0x%02X] msg\n",
3216 state->hdr.nbt[0]));
3218 req = state->req;
3219 ZERO_STRUCTP(state);
3220 state->req = req;
3221 state->min_recv_size = get_min_receive_file_size(state->req);
3222 req = NULL;
3223 goto again;
3226 req = state->req;
3227 state->req = NULL;
3229 req->request_time = timeval_current();
3230 now = timeval_to_nttime(&req->request_time);
3232 status = smbd_smb2_inbuf_parse_compound(req->sconn->conn,
3233 now,
3234 state->pktbuf,
3235 state->pktlen,
3236 req,
3237 &req->in.vector,
3238 &req->in.vector_count);
3239 if (!NT_STATUS_IS_OK(status)) {
3240 return status;
3243 if (state->doing_receivefile) {
3244 req->smb1req = talloc_zero(req, struct smb_request);
3245 if (req->smb1req == NULL) {
3246 return NT_STATUS_NO_MEMORY;
3248 req->smb1req->unread_bytes =
3249 state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3252 ZERO_STRUCTP(state);
3254 req->current_idx = 1;
3256 DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n",
3257 req->current_idx, req->in.vector_count));
3259 status = smbd_smb2_request_validate(req);
3260 if (!NT_STATUS_IS_OK(status)) {
3261 return status;
3264 status = smbd_smb2_request_setup_out(req);
3265 if (!NT_STATUS_IS_OK(status)) {
3266 return status;
3269 status = smbd_smb2_request_dispatch(req);
3270 if (!NT_STATUS_IS_OK(status)) {
3271 return status;
3274 sconn->num_requests++;
3276 /* The timeout_processing function isn't run nearly
3277 often enough to implement 'max log size' without
3278 overrunning the size of the file by many megabytes.
3279 This is especially true if we are running at debug
3280 level 10. Checking every 50 SMB2s is a nice
3281 tradeoff of performance vs log file size overrun. */
3283 if ((sconn->num_requests % 50) == 0 &&
3284 need_to_check_log_size()) {
3285 change_to_root_user();
3286 check_log_size();
3289 status = smbd_smb2_request_next_incoming(sconn);
3290 if (!NT_STATUS_IS_OK(status)) {
3291 return status;
3294 return NT_STATUS_OK;
3297 static void smbd_smb2_connection_handler(struct tevent_context *ev,
3298 struct tevent_fd *fde,
3299 uint16_t flags,
3300 void *private_data)
3302 struct smbd_server_connection *sconn =
3303 talloc_get_type_abort(private_data,
3304 struct smbd_server_connection);
3305 NTSTATUS status;
3307 status = smbd_smb2_io_handler(sconn, flags);
3308 if (!NT_STATUS_IS_OK(status)) {
3309 smbd_server_connection_terminate(sconn, nt_errstr(status));
3310 return;