s3:smb2_server: for performance reasons we use tevent_fd and readv/writev directly
[Samba.git] / source3 / smbd / smb2_server.c
blobf2703afe8a1999ff9c2ba8249efc0d194469a3b6
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_pool(mem_ctx, 8192);
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 TALLOC_FREE(mem_pool);
286 req->last_session_id = UINT64_MAX;
287 req->last_tid = UINT32_MAX;
289 talloc_set_destructor(req, smbd_smb2_request_destructor);
291 return req;
294 static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
295 NTTIME now,
296 uint8_t *buf,
297 size_t buflen,
298 TALLOC_CTX *mem_ctx,
299 struct iovec **piov,
300 int *pnum_iov)
302 struct iovec *iov;
303 int num_iov = 1;
304 size_t taken = 0;
305 uint8_t *first_hdr = buf;
306 size_t verified_buflen = 0;
307 uint8_t *tf = NULL;
308 size_t tf_len = 0;
311 * Note: index '0' is reserved for the transport protocol
313 iov = talloc_zero_array(mem_ctx, struct iovec, num_iov);
314 if (iov == NULL) {
315 return NT_STATUS_NO_MEMORY;
318 while (taken < buflen) {
319 size_t len = buflen - taken;
320 uint8_t *hdr = first_hdr + taken;
321 struct iovec *cur;
322 size_t full_size;
323 size_t next_command_ofs;
324 uint16_t body_size;
325 uint8_t *body = NULL;
326 uint32_t dyn_size;
327 uint8_t *dyn = NULL;
328 struct iovec *iov_tmp;
330 if (verified_buflen > taken) {
331 len = verified_buflen - taken;
332 } else {
333 tf = NULL;
334 tf_len = 0;
337 if (len < 4) {
338 DEBUG(10, ("%d bytes left, expected at least %d\n",
339 (int)len, 4));
340 goto inval;
342 if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
343 struct smbXsrv_session *s = NULL;
344 uint64_t uid;
345 struct iovec tf_iov[2];
346 NTSTATUS status;
347 size_t enc_len;
349 if (conn->protocol < PROTOCOL_SMB2_24) {
350 DEBUG(10, ("Got SMB2_TRANSFORM header, "
351 "but dialect[0x%04X] is used\n",
352 conn->smb2.server.dialect));
353 goto inval;
356 if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) {
357 DEBUG(10, ("Got SMB2_TRANSFORM header, "
358 "but not negotiated "
359 "client[0x%08X] server[0x%08X]\n",
360 conn->smb2.client.capabilities,
361 conn->smb2.server.capabilities));
362 goto inval;
365 if (len < SMB2_TF_HDR_SIZE) {
366 DEBUG(1, ("%d bytes left, expected at least %d\n",
367 (int)len, SMB2_TF_HDR_SIZE));
368 goto inval;
370 tf = hdr;
371 tf_len = SMB2_TF_HDR_SIZE;
372 taken += tf_len;
374 hdr = first_hdr + taken;
375 enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
376 uid = BVAL(tf, SMB2_TF_SESSION_ID);
378 if (len < SMB2_TF_HDR_SIZE + enc_len) {
379 DEBUG(1, ("%d bytes left, expected at least %d\n",
380 (int)len,
381 (int)(SMB2_TF_HDR_SIZE + enc_len)));
382 goto inval;
385 status = smb2srv_session_lookup(conn, uid, now, &s);
386 if (s == NULL) {
387 DEBUG(1, ("invalid session[%llu] in "
388 "SMB2_TRANSFORM header\n",
389 (unsigned long long)uid));
390 TALLOC_FREE(iov);
391 return NT_STATUS_USER_SESSION_DELETED;
394 tf_iov[0].iov_base = (void *)tf;
395 tf_iov[0].iov_len = tf_len;
396 tf_iov[1].iov_base = (void *)hdr;
397 tf_iov[1].iov_len = enc_len;
399 status = smb2_signing_decrypt_pdu(s->global->decryption_key,
400 conn->protocol,
401 tf_iov, 2);
402 if (!NT_STATUS_IS_OK(status)) {
403 TALLOC_FREE(iov);
404 return status;
407 verified_buflen = taken + enc_len;
408 len = enc_len;
412 * We need the header plus the body length field
415 if (len < SMB2_HDR_BODY + 2) {
416 DEBUG(10, ("%d bytes left, expected at least %d\n",
417 (int)len, SMB2_HDR_BODY));
418 goto inval;
420 if (IVAL(hdr, 0) != SMB2_MAGIC) {
421 DEBUG(10, ("Got non-SMB2 PDU: %x\n",
422 IVAL(hdr, 0)));
423 goto inval;
425 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
426 DEBUG(10, ("Got HDR len %d, expected %d\n",
427 SVAL(hdr, 4), SMB2_HDR_BODY));
428 goto inval;
431 full_size = len;
432 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
433 body_size = SVAL(hdr, SMB2_HDR_BODY);
435 if (next_command_ofs != 0) {
436 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
437 goto inval;
439 if (next_command_ofs > full_size) {
440 goto inval;
442 full_size = next_command_ofs;
444 if (body_size < 2) {
445 goto inval;
447 body_size &= 0xfffe;
449 if (body_size > (full_size - SMB2_HDR_BODY)) {
451 * let the caller handle the error
453 body_size = full_size - SMB2_HDR_BODY;
455 body = hdr + SMB2_HDR_BODY;
456 dyn = body + body_size;
457 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
459 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
460 num_iov + SMBD_SMB2_NUM_IOV_PER_REQ);
461 if (iov_tmp == NULL) {
462 TALLOC_FREE(iov);
463 return NT_STATUS_NO_MEMORY;
465 iov = iov_tmp;
466 cur = &iov[num_iov];
467 num_iov += SMBD_SMB2_NUM_IOV_PER_REQ;
469 cur[SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
470 cur[SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
471 cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
472 cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
473 cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
474 cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size;
475 cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
476 cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size;
478 taken += full_size;
481 *piov = iov;
482 *pnum_iov = num_iov;
483 return NT_STATUS_OK;
485 inval:
486 TALLOC_FREE(iov);
487 return NT_STATUS_INVALID_PARAMETER;
490 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
491 uint8_t *inbuf, size_t size,
492 struct smbd_smb2_request **_req)
494 struct smbd_smb2_request *req;
495 uint32_t protocol_version;
496 const uint8_t *inhdr = NULL;
497 uint16_t cmd;
498 uint32_t next_command_ofs;
499 NTSTATUS status;
500 NTTIME now;
502 if (size < (4 + SMB2_HDR_BODY + 2)) {
503 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
504 return NT_STATUS_INVALID_PARAMETER;
507 inhdr = inbuf + 4;
509 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
510 if (protocol_version != SMB2_MAGIC) {
511 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
512 protocol_version));
513 return NT_STATUS_INVALID_PARAMETER;
516 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
517 if (cmd != SMB2_OP_NEGPROT) {
518 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
519 cmd));
520 return NT_STATUS_INVALID_PARAMETER;
523 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
524 if (next_command_ofs != 0) {
525 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
526 next_command_ofs));
527 return NT_STATUS_INVALID_PARAMETER;
530 req = smbd_smb2_request_allocate(sconn);
531 if (req == NULL) {
532 return NT_STATUS_NO_MEMORY;
534 req->sconn = sconn;
536 talloc_steal(req, inbuf);
538 req->request_time = timeval_current();
539 now = timeval_to_nttime(&req->request_time);
541 status = smbd_smb2_inbuf_parse_compound(sconn->conn,
542 now,
543 inbuf + NBT_HDR_SIZE,
544 size - NBT_HDR_SIZE,
545 req, &req->in.vector,
546 &req->in.vector_count);
547 if (!NT_STATUS_IS_OK(status)) {
548 TALLOC_FREE(req);
549 return status;
552 req->current_idx = 1;
554 *_req = req;
555 return NT_STATUS_OK;
558 static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
559 uint64_t message_id, uint64_t seq_id)
561 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
562 unsigned int offset;
564 if (seq_id < sconn->smb2.seqnum_low) {
565 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
566 "%llu (sequence id %llu) "
567 "(granted = %u, low = %llu, range = %u)\n",
568 (unsigned long long)message_id,
569 (unsigned long long)seq_id,
570 (unsigned int)sconn->smb2.credits_granted,
571 (unsigned long long)sconn->smb2.seqnum_low,
572 (unsigned int)sconn->smb2.seqnum_range));
573 return false;
576 if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
577 DEBUG(0,("smb2_validate_sequence_number: bad message_id "
578 "%llu (sequence id %llu) "
579 "(granted = %u, low = %llu, range = %u)\n",
580 (unsigned long long)message_id,
581 (unsigned long long)seq_id,
582 (unsigned int)sconn->smb2.credits_granted,
583 (unsigned long long)sconn->smb2.seqnum_low,
584 (unsigned int)sconn->smb2.seqnum_range));
585 return false;
588 offset = seq_id % sconn->smb2.max_credits;
590 if (bitmap_query(credits_bm, offset)) {
591 DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
592 "%llu (sequence id %llu) "
593 "(granted = %u, low = %llu, range = %u) "
594 "(bm offset %u)\n",
595 (unsigned long long)message_id,
596 (unsigned long long)seq_id,
597 (unsigned int)sconn->smb2.credits_granted,
598 (unsigned long long)sconn->smb2.seqnum_low,
599 (unsigned int)sconn->smb2.seqnum_range,
600 offset));
601 return false;
604 /* Mark the message_ids as seen in the bitmap. */
605 bitmap_set(credits_bm, offset);
607 if (seq_id != sconn->smb2.seqnum_low) {
608 return true;
612 * Move the window forward by all the message_id's
613 * already seen.
615 while (bitmap_query(credits_bm, offset)) {
616 DEBUG(10,("smb2_validate_sequence_number: clearing "
617 "id %llu (position %u) from bitmap\n",
618 (unsigned long long)(sconn->smb2.seqnum_low),
619 offset));
620 bitmap_clear(credits_bm, offset);
622 sconn->smb2.seqnum_low += 1;
623 sconn->smb2.seqnum_range -= 1;
624 offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
627 return true;
630 static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
631 const uint8_t *inhdr)
633 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
634 uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
635 uint16_t credit_charge = 1;
636 uint64_t i;
638 if (opcode == SMB2_OP_CANCEL) {
639 /* SMB2_CANCEL requests by definition resend messageids. */
640 return true;
643 if (sconn->smb2.supports_multicredit) {
644 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
645 credit_charge = MAX(credit_charge, 1);
648 DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
649 "credits_granted %llu, "
650 "seqnum low/range: %llu/%llu\n",
651 (unsigned long long) message_id,
652 (unsigned long long) credit_charge,
653 (unsigned long long) sconn->smb2.credits_granted,
654 (unsigned long long) sconn->smb2.seqnum_low,
655 (unsigned long long) sconn->smb2.seqnum_range));
657 if (sconn->smb2.credits_granted < credit_charge) {
658 DEBUG(0, ("smb2_validate_message_id: client used more "
659 "credits than granted, mid %llu, charge %llu, "
660 "credits_granted %llu, "
661 "seqnum low/range: %llu/%llu\n",
662 (unsigned long long) message_id,
663 (unsigned long long) credit_charge,
664 (unsigned long long) sconn->smb2.credits_granted,
665 (unsigned long long) sconn->smb2.seqnum_low,
666 (unsigned long long) sconn->smb2.seqnum_range));
667 return false;
671 * now check the message ids
673 * for multi-credit requests we need to check all current mid plus
674 * the implicit mids caused by the credit charge
675 * e.g. current mid = 15, charge 5 => mark 15-19 as used
678 for (i = 0; i <= (credit_charge-1); i++) {
679 uint64_t id = message_id + i;
680 bool ok;
682 DEBUG(11, ("Iterating mid %llu charge %u (sequence %llu)\n",
683 (unsigned long long)message_id,
684 credit_charge,
685 (unsigned long long)id));
687 ok = smb2_validate_sequence_number(sconn, message_id, id);
688 if (!ok) {
689 return false;
693 /* substract used credits */
694 sconn->smb2.credits_granted -= credit_charge;
696 return true;
699 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
701 int count;
702 int idx;
704 count = req->in.vector_count;
706 if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
707 /* It's not a SMB2 request */
708 return NT_STATUS_INVALID_PARAMETER;
711 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
712 struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
713 struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
714 const uint8_t *inhdr = NULL;
716 if (hdr->iov_len != SMB2_HDR_BODY) {
717 return NT_STATUS_INVALID_PARAMETER;
720 if (body->iov_len < 2) {
721 return NT_STATUS_INVALID_PARAMETER;
724 inhdr = (const uint8_t *)hdr->iov_base;
726 /* Check the SMB2 header */
727 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
728 return NT_STATUS_INVALID_PARAMETER;
731 if (!smb2_validate_message_id(req->sconn, inhdr)) {
732 return NT_STATUS_INVALID_PARAMETER;
736 return NT_STATUS_OK;
739 static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
740 const struct iovec *in_vector,
741 struct iovec *out_vector)
743 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
744 uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
745 uint16_t credit_charge = 1;
746 uint16_t credits_requested;
747 uint32_t out_flags;
748 uint16_t cmd;
749 NTSTATUS out_status;
750 uint16_t credits_granted = 0;
751 uint64_t credits_possible;
752 uint16_t current_max_credits;
755 * first we grant only 1/16th of the max range.
757 * Windows also starts with the 1/16th and then grants
758 * more later. I was only able to trigger higher
759 * values, when using a very high credit charge.
761 * TODO: scale up depending on load, free memory
762 * or other stuff.
763 * Maybe also on the relationship between number
764 * of requests and the used sequence number.
765 * Which means we would grant more credits
766 * for client which use multi credit requests.
768 current_max_credits = sconn->smb2.max_credits / 16;
769 current_max_credits = MAX(current_max_credits, 1);
771 if (sconn->smb2.supports_multicredit) {
772 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
773 credit_charge = MAX(credit_charge, 1);
776 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
777 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
778 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
779 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
781 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
783 if (sconn->smb2.max_credits < credit_charge) {
784 smbd_server_connection_terminate(sconn,
785 "client error: credit charge > max credits\n");
786 return;
789 if (out_flags & SMB2_HDR_FLAG_ASYNC) {
791 * In case we already send an async interim
792 * response, we should not grant
793 * credits on the final response.
795 credits_granted = 0;
796 } else if (credits_requested > 0) {
797 uint16_t additional_max = 0;
798 uint16_t additional_credits = credits_requested - 1;
800 switch (cmd) {
801 case SMB2_OP_NEGPROT:
802 break;
803 case SMB2_OP_SESSSETUP:
805 * Windows 2012 RC1 starts to grant
806 * additional credits
807 * with a successful session setup
809 if (NT_STATUS_IS_OK(out_status)) {
810 additional_max = 32;
812 break;
813 default:
815 * We match windows and only grant additional credits
816 * in chunks of 32.
818 additional_max = 32;
819 break;
822 additional_credits = MIN(additional_credits, additional_max);
824 credits_granted = credit_charge + additional_credits;
825 } else if (sconn->smb2.credits_granted == 0) {
827 * Make sure the client has always at least one credit
829 credits_granted = 1;
833 * sequence numbers should not wrap
835 * 1. calculate the possible credits until
836 * the sequence numbers start to wrap on 64-bit.
838 * 2. UINT64_MAX is used for Break Notifications.
840 * 2. truncate the possible credits to the maximum
841 * credits we want to grant to the client in total.
843 * 3. remove the range we'll already granted to the client
844 * this makes sure the client consumes the lowest sequence
845 * number, before we can grant additional credits.
847 credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
848 if (credits_possible > 0) {
849 /* remove UINT64_MAX */
850 credits_possible -= 1;
852 credits_possible = MIN(credits_possible, current_max_credits);
853 credits_possible -= sconn->smb2.seqnum_range;
855 credits_granted = MIN(credits_granted, credits_possible);
857 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
858 sconn->smb2.credits_granted += credits_granted;
859 sconn->smb2.seqnum_range += credits_granted;
861 DEBUG(10,("smb2_set_operation_credit: requested %u, charge %u, "
862 "granted %u, current possible/max %u/%u, "
863 "total granted/max/low/range %u/%u/%llu/%u\n",
864 (unsigned int)credits_requested,
865 (unsigned int)credit_charge,
866 (unsigned int)credits_granted,
867 (unsigned int)credits_possible,
868 (unsigned int)current_max_credits,
869 (unsigned int)sconn->smb2.credits_granted,
870 (unsigned int)sconn->smb2.max_credits,
871 (unsigned long long)sconn->smb2.seqnum_low,
872 (unsigned int)sconn->smb2.seqnum_range));
875 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
876 struct smbd_smb2_request *outreq)
878 int count, idx;
879 uint16_t total_credits = 0;
881 count = outreq->out.vector_count;
883 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
884 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx);
885 struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx);
886 uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base;
888 smb2_set_operation_credit(outreq->sconn, inhdr_v, outhdr_v);
890 /* To match Windows, count up what we
891 just granted. */
892 total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
893 /* Set to zero in all but the last reply. */
894 if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) {
895 SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
896 } else {
897 SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
902 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
904 struct iovec *vector;
905 int count;
906 int idx;
908 count = req->in.vector_count;
909 vector = talloc_zero_array(req, struct iovec, count);
910 if (vector == NULL) {
911 return NT_STATUS_NO_MEMORY;
914 vector[0].iov_base = req->out.nbt_hdr;
915 vector[0].iov_len = 4;
916 SIVAL(req->out.nbt_hdr, 0, 0);
918 for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) {
919 struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
920 const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base;
921 uint8_t *outhdr = NULL;
922 uint8_t *outbody = NULL;
923 uint32_t next_command_ofs = 0;
924 struct iovec *current = &vector[idx];
926 if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) {
927 /* we have a next command -
928 * setup for the error case. */
929 next_command_ofs = SMB2_HDR_BODY + 9;
932 outhdr = talloc_zero_array(vector, uint8_t,
933 OUTVEC_ALLOC_SIZE);
934 if (outhdr == NULL) {
935 return NT_STATUS_NO_MEMORY;
938 outbody = outhdr + SMB2_HDR_BODY;
941 * SMBD_SMB2_TF_IOV_OFS might be used later
943 current[SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
944 current[SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
946 current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr;
947 current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
949 current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody;
950 current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
952 current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL;
953 current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0;
955 /* setup the SMB2 header */
956 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
957 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
958 SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
959 SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
960 SIVAL(outhdr, SMB2_HDR_STATUS,
961 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
962 SSVAL(outhdr, SMB2_HDR_OPCODE,
963 SVAL(inhdr, SMB2_HDR_OPCODE));
964 SIVAL(outhdr, SMB2_HDR_FLAGS,
965 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
966 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
967 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
968 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
969 SIVAL(outhdr, SMB2_HDR_PID,
970 IVAL(inhdr, SMB2_HDR_PID));
971 SIVAL(outhdr, SMB2_HDR_TID,
972 IVAL(inhdr, SMB2_HDR_TID));
973 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
974 BVAL(inhdr, SMB2_HDR_SESSION_ID));
975 memcpy(outhdr + SMB2_HDR_SIGNATURE,
976 inhdr + SMB2_HDR_SIGNATURE, 16);
978 /* setup error body header */
979 SSVAL(outbody, 0x00, 0x08 + 1);
980 SSVAL(outbody, 0x02, 0);
981 SIVAL(outbody, 0x04, 0);
984 req->out.vector = vector;
985 req->out.vector_count = count;
987 /* setup the length of the NBT packet */
988 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
990 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
992 return NT_STATUS_OK;
995 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
996 const char *reason,
997 const char *location)
999 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
1000 reason, location));
1001 exit_server_cleanly(reason);
1004 static bool dup_smb2_vec4(TALLOC_CTX *ctx,
1005 struct iovec *outvec,
1006 const struct iovec *srcvec)
1008 const uint8_t *srctf;
1009 size_t srctf_len;
1010 const uint8_t *srchdr;
1011 size_t srchdr_len;
1012 const uint8_t *srcbody;
1013 size_t srcbody_len;
1014 const uint8_t *expected_srcbody;
1015 const uint8_t *srcdyn;
1016 size_t srcdyn_len;
1017 const uint8_t *expected_srcdyn;
1018 uint8_t *dsttf;
1019 uint8_t *dsthdr;
1020 uint8_t *dstbody;
1021 uint8_t *dstdyn;
1023 srctf = (const uint8_t *)srcvec[SMBD_SMB2_TF_IOV_OFS].iov_base;
1024 srctf_len = srcvec[SMBD_SMB2_TF_IOV_OFS].iov_len;
1025 srchdr = (const uint8_t *)srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base;
1026 srchdr_len = srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_len;
1027 srcbody = (const uint8_t *)srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_base;
1028 srcbody_len = srcvec[SMBD_SMB2_BODY_IOV_OFS].iov_len;
1029 expected_srcbody = srchdr + SMB2_HDR_BODY;
1030 srcdyn = (const uint8_t *)srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_base;
1031 srcdyn_len = srcvec[SMBD_SMB2_DYN_IOV_OFS].iov_len;
1032 expected_srcdyn = srcbody + 8;
1034 if ((srctf_len != SMB2_TF_HDR_SIZE) && (srctf_len != 0)) {
1035 return false;
1038 if (srchdr_len != SMB2_HDR_BODY) {
1039 return false;
1042 if (srctf_len == SMB2_TF_HDR_SIZE) {
1043 dsttf = talloc_memdup(ctx, srctf, SMB2_TF_HDR_SIZE);
1044 if (dsttf == NULL) {
1045 return false;
1047 } else {
1048 dsttf = NULL;
1050 outvec[SMBD_SMB2_TF_IOV_OFS].iov_base = (void *)dsttf;
1051 outvec[SMBD_SMB2_TF_IOV_OFS].iov_len = srctf_len;
1053 /* vec[SMBD_SMB2_HDR_IOV_OFS] is always boilerplate and must
1054 * be allocated with size OUTVEC_ALLOC_SIZE. */
1056 dsthdr = talloc_memdup(ctx, srchdr, OUTVEC_ALLOC_SIZE);
1057 if (dsthdr == NULL) {
1058 return false;
1060 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)dsthdr;
1061 outvec[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1064 * If this is a "standard" vec[SMBD_SMB2_BOFY_IOV_OFS] of length 8,
1065 * pointing to srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + SMB2_HDR_BODY,
1066 * then duplicate this. Else use talloc_memdup().
1069 if ((srcbody == expected_srcbody) && (srcbody_len == 8)) {
1070 dstbody = dsthdr + SMB2_HDR_BODY;
1071 } else {
1072 dstbody = talloc_memdup(ctx, srcbody, srcbody_len);
1073 if (dstbody == NULL) {
1074 return false;
1077 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)dstbody;
1078 outvec[SMBD_SMB2_BODY_IOV_OFS].iov_len = srcbody_len;
1081 * If this is a "standard" vec[SMBD_SMB2_DYN_IOV_OFS] of length 1,
1082 * pointing to
1083 * srcvec[SMBD_SMB2_HDR_IOV_OFS].iov_base + 8
1084 * then duplicate this. Else use talloc_memdup().
1087 if ((srcdyn == expected_srcdyn) && (srcdyn_len == 1)) {
1088 dstdyn = dsthdr + SMB2_HDR_BODY + 8;
1089 } else if (srcdyn == NULL) {
1090 dstdyn = NULL;
1091 } else {
1092 dstdyn = talloc_memdup(ctx, srcdyn, srcdyn_len);
1093 if (dstdyn == NULL) {
1094 return false;
1097 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_base = (void *)dstdyn;
1098 outvec[SMBD_SMB2_DYN_IOV_OFS].iov_len = srcdyn_len;
1100 return true;
1103 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
1105 struct smbd_smb2_request *newreq = NULL;
1106 struct iovec *outvec = NULL;
1107 int count = req->out.vector_count;
1108 int i;
1110 newreq = smbd_smb2_request_allocate(req->sconn);
1111 if (!newreq) {
1112 return NULL;
1115 newreq->sconn = req->sconn;
1116 newreq->session = req->session;
1117 newreq->do_encryption = req->do_encryption;
1118 newreq->do_signing = req->do_signing;
1119 newreq->current_idx = req->current_idx;
1121 outvec = talloc_zero_array(newreq, struct iovec, count);
1122 if (!outvec) {
1123 TALLOC_FREE(newreq);
1124 return NULL;
1126 newreq->out.vector = outvec;
1127 newreq->out.vector_count = count;
1129 /* Setup the outvec's identically to req. */
1130 outvec[0].iov_base = newreq->out.nbt_hdr;
1131 outvec[0].iov_len = 4;
1132 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
1134 /* Setup the vectors identically to the ones in req. */
1135 for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) {
1136 if (!dup_smb2_vec4(outvec, &outvec[i], &req->out.vector[i])) {
1137 break;
1141 if (i < count) {
1142 /* Alloc failed. */
1143 TALLOC_FREE(newreq);
1144 return NULL;
1147 smb2_setup_nbt_length(newreq->out.vector,
1148 newreq->out.vector_count);
1150 return newreq;
1153 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
1155 struct smbd_server_connection *sconn = req->sconn;
1156 struct smbXsrv_connection *conn = req->sconn->conn;
1157 int first_idx = 1;
1158 struct iovec *firsttf = NULL;
1159 struct iovec *outhdr_v = NULL;
1160 uint8_t *outhdr = NULL;
1161 struct smbd_smb2_request *nreq = NULL;
1162 NTSTATUS status;
1164 /* Create a new smb2 request we'll use
1165 for the interim return. */
1166 nreq = dup_smb2_req(req);
1167 if (!nreq) {
1168 return NT_STATUS_NO_MEMORY;
1171 /* Lose the last X out vectors. They're the
1172 ones we'll be using for the async reply. */
1173 nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ;
1175 smb2_setup_nbt_length(nreq->out.vector,
1176 nreq->out.vector_count);
1178 /* Step back to the previous reply. */
1179 nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ;
1180 firsttf = SMBD_SMB2_IDX_TF_IOV(nreq,out,first_idx);
1181 outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq);
1182 outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq);
1183 /* And end the chain. */
1184 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
1186 /* Calculate outgoing credits */
1187 smb2_calculate_credits(req, nreq);
1189 if (DEBUGLEVEL >= 10) {
1190 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
1191 (unsigned int)nreq->current_idx );
1192 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
1193 (unsigned int)nreq->out.vector_count );
1194 print_req_vectors(nreq);
1198 * As we have changed the header (SMB2_HDR_NEXT_COMMAND),
1199 * we need to sign/encrypt here with the last/first key we remembered
1201 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
1202 status = smb2_signing_encrypt_pdu(req->first_key,
1203 conn->protocol,
1204 firsttf,
1205 nreq->out.vector_count - first_idx);
1206 if (!NT_STATUS_IS_OK(status)) {
1207 return status;
1209 } else if (req->last_key.length > 0) {
1210 status = smb2_signing_sign_pdu(req->last_key,
1211 conn->protocol,
1212 outhdr_v,
1213 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 return status;
1219 nreq->queue_entry.mem_ctx = nreq;
1220 nreq->queue_entry.vector = nreq->out.vector;
1221 nreq->queue_entry.count = nreq->out.vector_count;
1222 DLIST_ADD_END(nreq->sconn->smb2.send_queue, &nreq->queue_entry, NULL);
1223 nreq->sconn->smb2.send_queue_len++;
1225 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 return status;
1230 return NT_STATUS_OK;
1233 struct smbd_smb2_request_pending_state {
1234 struct smbd_server_connection *sconn;
1235 struct smbd_smb2_send_queue queue_entry;
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_timer(struct tevent_context *ev,
1241 struct tevent_timer *te,
1242 struct timeval current_time,
1243 void *private_data);
1245 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
1246 struct tevent_req *subreq,
1247 uint32_t defer_time)
1249 NTSTATUS status;
1250 struct timeval defer_endtime;
1251 uint8_t *outhdr = NULL;
1252 uint32_t flags;
1254 if (!tevent_req_is_in_progress(subreq)) {
1255 return NT_STATUS_OK;
1258 req->subreq = subreq;
1259 subreq = NULL;
1261 if (req->async_te) {
1262 /* We're already async. */
1263 return NT_STATUS_OK;
1266 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1267 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1268 if (flags & SMB2_HDR_FLAG_ASYNC) {
1269 /* We're already async. */
1270 return NT_STATUS_OK;
1273 if (req->in.vector_count > req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1275 * We're trying to go async in a compound
1276 * request chain.
1277 * This is only allowed for opens that
1278 * cause an oplock break, otherwise it
1279 * is not allowed. See [MS-SMB2].pdf
1280 * note <194> on Section 3.3.5.2.7.
1282 const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1284 if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_CREATE) {
1286 * Cancel the outstanding request.
1288 bool ok = tevent_req_cancel(req->subreq);
1289 if (ok) {
1290 return NT_STATUS_OK;
1292 TALLOC_FREE(req->subreq);
1293 return smbd_smb2_request_error(req,
1294 NT_STATUS_INTERNAL_ERROR);
1298 if (DEBUGLEVEL >= 10) {
1299 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1300 (unsigned int)req->current_idx );
1301 print_req_vectors(req);
1304 if (req->current_idx > 1) {
1306 * We're going async in a compound
1307 * chain after the first request has
1308 * already been processed. Send an
1309 * interim response containing the
1310 * set of replies already generated.
1312 int idx = req->current_idx;
1314 status = smb2_send_async_interim_response(req);
1315 if (!NT_STATUS_IS_OK(status)) {
1316 return status;
1318 data_blob_clear_free(&req->first_key);
1320 req->current_idx = 1;
1323 * Re-arrange the in.vectors to remove what
1324 * we just sent.
1326 memmove(&req->in.vector[1],
1327 &req->in.vector[idx],
1328 sizeof(req->in.vector[0])*(req->in.vector_count - idx));
1329 req->in.vector_count = 1 + (req->in.vector_count - idx);
1331 /* Re-arrange the out.vectors to match. */
1332 memmove(&req->out.vector[1],
1333 &req->out.vector[idx],
1334 sizeof(req->out.vector[0])*(req->out.vector_count - idx));
1335 req->out.vector_count = 1 + (req->out.vector_count - idx);
1337 if (req->in.vector_count == 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
1339 * We only have one remaining request as
1340 * we've processed everything else.
1341 * This is no longer a compound request.
1343 req->compound_related = false;
1344 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1345 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1346 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1349 data_blob_clear_free(&req->last_key);
1351 defer_endtime = timeval_current_ofs_usec(defer_time);
1352 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1353 req, defer_endtime,
1354 smbd_smb2_request_pending_timer,
1355 req);
1356 if (req->async_te == NULL) {
1357 return NT_STATUS_NO_MEMORY;
1360 return NT_STATUS_OK;
1363 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1364 struct tevent_timer *te,
1365 struct timeval current_time,
1366 void *private_data)
1368 struct smbd_smb2_request *req =
1369 talloc_get_type_abort(private_data,
1370 struct smbd_smb2_request);
1371 struct smbd_server_connection *sconn = req->sconn;
1372 struct smbd_smb2_request_pending_state *state = NULL;
1373 uint8_t *outhdr = NULL;
1374 const uint8_t *inhdr = NULL;
1375 uint8_t *tf = NULL;
1376 size_t tf_len = 0;
1377 uint8_t *hdr = NULL;
1378 uint8_t *body = NULL;
1379 uint8_t *dyn = NULL;
1380 uint32_t flags = 0;
1381 uint64_t session_id = 0;
1382 uint64_t message_id = 0;
1383 uint64_t nonce_high = 0;
1384 uint64_t nonce_low = 0;
1385 uint64_t async_id = 0;
1386 NTSTATUS status;
1388 TALLOC_FREE(req->async_te);
1390 /* Ensure our final reply matches the interim one. */
1391 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1392 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1393 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1394 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1395 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1397 async_id = message_id; /* keep it simple for now... */
1399 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1400 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1402 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1403 "going async\n",
1404 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1405 (unsigned long long)async_id ));
1408 * What we send is identical to a smbd_smb2_request_error
1409 * packet with an error status of STATUS_PENDING. Make use
1410 * of this fact sometime when refactoring. JRA.
1413 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1414 if (state == NULL) {
1415 smbd_server_connection_terminate(req->sconn,
1416 nt_errstr(NT_STATUS_NO_MEMORY));
1417 return;
1419 state->sconn = req->sconn;
1421 tf = state->buf + NBT_HDR_SIZE;
1422 tf_len = SMB2_TF_HDR_SIZE;
1424 hdr = tf + SMB2_TF_HDR_SIZE;
1425 body = hdr + SMB2_HDR_BODY;
1426 dyn = body + 8;
1428 if (req->do_encryption) {
1429 struct smbXsrv_session *x = req->session;
1431 nonce_high = x->nonce_high;
1432 nonce_low = x->nonce_low;
1434 x->nonce_low += 1;
1435 if (x->nonce_low == 0) {
1436 x->nonce_low += 1;
1437 x->nonce_high += 1;
1441 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1442 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1443 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1444 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1446 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1447 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1448 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1449 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1450 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1452 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1453 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1454 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1455 SBVAL(hdr, SMB2_HDR_PID, async_id);
1456 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1457 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1458 memcpy(hdr+SMB2_HDR_SIGNATURE,
1459 outhdr+SMB2_HDR_SIGNATURE, 16);
1461 SSVAL(body, 0x00, 0x08 + 1);
1463 SCVAL(body, 0x02, 0);
1464 SCVAL(body, 0x03, 0);
1465 SIVAL(body, 0x04, 0);
1466 /* Match W2K8R2... */
1467 SCVAL(dyn, 0x00, 0x21);
1469 state->vector[0].iov_base = (void *)state->buf;
1470 state->vector[0].iov_len = NBT_HDR_SIZE;
1472 if (req->do_encryption) {
1473 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1474 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1475 } else {
1476 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1477 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1480 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1481 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1483 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1484 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1486 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1487 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1489 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1491 /* Ensure we correctly go through crediting. Grant
1492 the credits now, and zero credits on the final
1493 response. */
1494 smb2_set_operation_credit(req->sconn,
1495 SMBD_SMB2_IN_HDR_IOV(req),
1496 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1498 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1500 if (DEBUGLVL(10)) {
1501 int i;
1503 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1504 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1505 (unsigned int)i,
1506 (unsigned int)ARRAY_SIZE(state->vector),
1507 (unsigned int)state->vector[i].iov_len);
1511 if (req->do_encryption) {
1512 struct smbXsrv_session *x = req->session;
1513 struct smbXsrv_connection *conn = x->connection;
1514 DATA_BLOB encryption_key = x->global->encryption_key;
1516 status = smb2_signing_encrypt_pdu(encryption_key,
1517 conn->protocol,
1518 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1519 SMBD_SMB2_NUM_IOV_PER_REQ);
1520 if (!NT_STATUS_IS_OK(status)) {
1521 smbd_server_connection_terminate(req->sconn,
1522 nt_errstr(status));
1523 return;
1525 } else if (req->do_signing) {
1526 struct smbXsrv_session *x = req->session;
1527 struct smbXsrv_connection *conn = x->connection;
1528 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1530 status = smb2_signing_sign_pdu(signing_key,
1531 conn->protocol,
1532 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1533 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1534 if (!NT_STATUS_IS_OK(status)) {
1535 smbd_server_connection_terminate(req->sconn,
1536 nt_errstr(status));
1537 return;
1541 state->queue_entry.mem_ctx = state;
1542 state->queue_entry.vector = state->vector;
1543 state->queue_entry.count = ARRAY_SIZE(state->vector);
1544 DLIST_ADD_END(sconn->smb2.send_queue, &state->queue_entry, NULL);
1545 sconn->smb2.send_queue_len++;
1547 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
1548 if (!NT_STATUS_IS_OK(status)) {
1549 smbd_server_connection_terminate(sconn,
1550 nt_errstr(status));
1551 return;
1555 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1557 struct smbd_server_connection *sconn = req->sconn;
1558 struct smbd_smb2_request *cur;
1559 const uint8_t *inhdr;
1560 uint32_t flags;
1561 uint64_t search_message_id;
1562 uint64_t search_async_id;
1563 uint64_t found_id;
1565 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1567 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1568 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1569 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1572 * we don't need the request anymore
1573 * cancel requests never have a response
1575 DLIST_REMOVE(req->sconn->smb2.requests, req);
1576 TALLOC_FREE(req);
1578 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1579 const uint8_t *outhdr;
1580 uint64_t message_id;
1581 uint64_t async_id;
1583 if (cur->compound_related) {
1585 * Never cancel anything in a compound request.
1586 * Way too hard to deal with the result.
1588 continue;
1591 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1593 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1594 async_id = BVAL(outhdr, SMB2_HDR_PID);
1596 if (flags & SMB2_HDR_FLAG_ASYNC) {
1597 if (search_async_id == async_id) {
1598 found_id = async_id;
1599 break;
1601 } else {
1602 if (search_message_id == message_id) {
1603 found_id = message_id;
1604 break;
1609 if (cur && cur->subreq) {
1610 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1611 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1612 "cancel opcode[%s] mid %llu\n",
1613 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1614 (unsigned long long)found_id ));
1615 tevent_req_cancel(cur->subreq);
1618 return NT_STATUS_OK;
1621 /*************************************************************
1622 Ensure an incoming tid is a valid one for us to access.
1623 Change to the associated uid credentials and chdir to the
1624 valid tid directory.
1625 *************************************************************/
1627 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1629 const uint8_t *inhdr;
1630 uint32_t in_flags;
1631 uint32_t in_tid;
1632 struct smbXsrv_tcon *tcon;
1633 NTSTATUS status;
1634 NTTIME now = timeval_to_nttime(&req->request_time);
1636 req->tcon = NULL;
1638 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1640 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1641 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1643 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1644 in_tid = req->last_tid;
1647 req->last_tid = 0;
1649 status = smb2srv_tcon_lookup(req->session,
1650 in_tid, now, &tcon);
1651 if (!NT_STATUS_IS_OK(status)) {
1652 return status;
1655 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1656 return NT_STATUS_ACCESS_DENIED;
1659 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1660 if (!set_current_service(tcon->compat, 0, true)) {
1661 return NT_STATUS_ACCESS_DENIED;
1664 req->tcon = tcon;
1665 req->last_tid = in_tid;
1667 return NT_STATUS_OK;
1670 /*************************************************************
1671 Ensure an incoming session_id is a valid one for us to access.
1672 *************************************************************/
1674 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1676 const uint8_t *inhdr;
1677 uint32_t in_flags;
1678 uint16_t in_opcode;
1679 uint64_t in_session_id;
1680 struct smbXsrv_session *session = NULL;
1681 struct auth_session_info *session_info;
1682 NTSTATUS status;
1683 NTTIME now = timeval_to_nttime(&req->request_time);
1685 req->session = NULL;
1686 req->tcon = NULL;
1688 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1690 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1691 in_opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1692 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1694 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1695 in_session_id = req->last_session_id;
1698 req->last_session_id = 0;
1700 /* lookup an existing session */
1701 status = smb2srv_session_lookup(req->sconn->conn,
1702 in_session_id, now,
1703 &session);
1704 if (session) {
1705 req->session = session;
1706 req->last_session_id = in_session_id;
1708 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1709 switch (in_opcode) {
1710 case SMB2_OP_SESSSETUP:
1711 status = NT_STATUS_OK;
1712 break;
1713 default:
1714 break;
1717 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1718 switch (in_opcode) {
1719 case SMB2_OP_TCON:
1720 case SMB2_OP_CREATE:
1721 case SMB2_OP_GETINFO:
1722 case SMB2_OP_SETINFO:
1723 return NT_STATUS_INVALID_HANDLE;
1724 default:
1726 * Notice the check for
1727 * (session_info == NULL)
1728 * below.
1730 status = NT_STATUS_OK;
1731 break;
1734 if (!NT_STATUS_IS_OK(status)) {
1735 return status;
1738 session_info = session->global->auth_session_info;
1739 if (session_info == NULL) {
1740 return NT_STATUS_INVALID_HANDLE;
1743 set_current_user_info(session_info->unix_info->sanitized_username,
1744 session_info->unix_info->unix_name,
1745 session_info->info->domain_name);
1747 return NT_STATUS_OK;
1750 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1751 uint32_t data_length)
1753 uint16_t needed_charge;
1754 uint16_t credit_charge = 1;
1755 const uint8_t *inhdr;
1757 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1759 if (req->sconn->smb2.supports_multicredit) {
1760 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1761 credit_charge = MAX(credit_charge, 1);
1764 needed_charge = (data_length - 1)/ 65536 + 1;
1766 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1767 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1768 credit_charge, needed_charge));
1770 if (needed_charge > credit_charge) {
1771 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1772 credit_charge, needed_charge));
1773 return NT_STATUS_INVALID_PARAMETER;
1776 return NT_STATUS_OK;
1779 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1780 size_t expected_body_size)
1782 struct iovec *inhdr_v;
1783 const uint8_t *inhdr;
1784 uint16_t opcode;
1785 const uint8_t *inbody;
1786 size_t body_size;
1787 size_t min_dyn_size = expected_body_size & 0x00000001;
1788 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1791 * The following should be checked already.
1793 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1794 return NT_STATUS_INTERNAL_ERROR;
1796 if (req->current_idx > max_idx) {
1797 return NT_STATUS_INTERNAL_ERROR;
1800 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1801 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1802 return NT_STATUS_INTERNAL_ERROR;
1804 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1805 return NT_STATUS_INTERNAL_ERROR;
1808 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1809 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1811 switch (opcode) {
1812 case SMB2_OP_IOCTL:
1813 case SMB2_OP_GETINFO:
1814 min_dyn_size = 0;
1815 break;
1819 * Now check the expected body size,
1820 * where the last byte might be in the
1821 * dynamic section..
1823 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1824 return NT_STATUS_INVALID_PARAMETER;
1826 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1827 return NT_STATUS_INVALID_PARAMETER;
1830 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1832 body_size = SVAL(inbody, 0x00);
1833 if (body_size != expected_body_size) {
1834 return NT_STATUS_INVALID_PARAMETER;
1837 return NT_STATUS_OK;
1840 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1842 struct smbXsrv_connection *conn = req->sconn->conn;
1843 const struct smbd_smb2_dispatch_table *call = NULL;
1844 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1845 const uint8_t *inhdr;
1846 uint16_t opcode;
1847 uint32_t flags;
1848 uint64_t mid;
1849 NTSTATUS status;
1850 NTSTATUS session_status;
1851 uint32_t allowed_flags;
1852 NTSTATUS return_value;
1853 struct smbXsrv_session *x = NULL;
1854 bool signing_required = false;
1855 bool encryption_required = false;
1857 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1859 /* TODO: verify more things */
1861 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1862 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1863 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1864 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1865 smb2_opcode_name(opcode),
1866 (unsigned long long)mid));
1868 if (conn->protocol >= PROTOCOL_SMB2_02) {
1870 * once the protocol is negotiated
1871 * SMB2_OP_NEGPROT is not allowed anymore
1873 if (opcode == SMB2_OP_NEGPROT) {
1874 /* drop the connection */
1875 return NT_STATUS_INVALID_PARAMETER;
1877 } else {
1879 * if the protocol is not negotiated yet
1880 * only SMB2_OP_NEGPROT is allowed.
1882 if (opcode != SMB2_OP_NEGPROT) {
1883 /* drop the connection */
1884 return NT_STATUS_INVALID_PARAMETER;
1889 * Check if the client provided a valid session id,
1890 * if so smbd_smb2_request_check_session() calls
1891 * set_current_user_info().
1893 * As some command don't require a valid session id
1894 * we defer the check of the session_status
1896 session_status = smbd_smb2_request_check_session(req);
1897 x = req->session;
1898 if (x != NULL) {
1899 signing_required = x->global->signing_required;
1900 encryption_required = x->global->encryption_required;
1902 if (opcode == SMB2_OP_SESSSETUP &&
1903 x->global->channels[0].signing_key.length) {
1904 signing_required = true;
1908 req->do_signing = false;
1909 req->do_encryption = false;
1910 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1911 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1912 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1914 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1915 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1916 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1917 (unsigned long long)x->global->session_wire_id,
1918 (unsigned long long)tf_session_id));
1920 * TODO: windows allows this...
1921 * should we drop the connection?
1923 * For now we just return ACCESS_DENIED
1924 * (Windows clients never trigger this)
1925 * and wait for an update of [MS-SMB2].
1927 return smbd_smb2_request_error(req,
1928 NT_STATUS_ACCESS_DENIED);
1931 req->do_encryption = true;
1934 if (encryption_required && !req->do_encryption) {
1935 return smbd_smb2_request_error(req,
1936 NT_STATUS_ACCESS_DENIED);
1939 call = smbd_smb2_call(opcode);
1940 if (call == NULL) {
1941 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1944 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1945 SMB2_HDR_FLAG_SIGNED |
1946 SMB2_HDR_FLAG_DFS;
1947 if (opcode == SMB2_OP_CANCEL) {
1948 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1950 if ((flags & ~allowed_flags) != 0) {
1951 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1954 if (flags & SMB2_HDR_FLAG_CHAINED) {
1956 * This check is mostly for giving the correct error code
1957 * for compounded requests.
1959 if (!NT_STATUS_IS_OK(session_status)) {
1960 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1962 } else {
1963 req->compat_chain_fsp = NULL;
1966 if (req->do_encryption) {
1967 signing_required = false;
1968 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1969 DATA_BLOB signing_key;
1971 if (x == NULL) {
1972 return smbd_smb2_request_error(
1973 req, NT_STATUS_ACCESS_DENIED);
1976 signing_key = x->global->channels[0].signing_key;
1979 * If we have a signing key, we should
1980 * sign the response
1982 if (signing_key.length > 0) {
1983 req->do_signing = true;
1986 status = smb2_signing_check_pdu(signing_key,
1987 conn->protocol,
1988 SMBD_SMB2_IN_HDR_IOV(req),
1989 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1990 if (!NT_STATUS_IS_OK(status)) {
1991 return smbd_smb2_request_error(req, status);
1995 * Now that we know the request was correctly signed
1996 * we have to sign the response too.
1998 req->do_signing = true;
2000 if (!NT_STATUS_IS_OK(session_status)) {
2001 return smbd_smb2_request_error(req, session_status);
2003 } else if (opcode == SMB2_OP_CANCEL) {
2004 /* Cancel requests are allowed to skip the signing */
2005 } else if (signing_required) {
2007 * If signing is required we try to sign
2008 * a possible error response
2010 req->do_signing = true;
2011 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2014 if (flags & SMB2_HDR_FLAG_CHAINED) {
2015 req->compound_related = true;
2018 if (call->need_session) {
2019 if (!NT_STATUS_IS_OK(session_status)) {
2020 return smbd_smb2_request_error(req, session_status);
2024 if (call->need_tcon) {
2025 SMB_ASSERT(call->need_session);
2028 * This call needs to be run as user.
2030 * smbd_smb2_request_check_tcon()
2031 * calls change_to_user() on success.
2033 status = smbd_smb2_request_check_tcon(req);
2034 if (!NT_STATUS_IS_OK(status)) {
2035 return smbd_smb2_request_error(req, status);
2037 if (req->tcon->global->encryption_required) {
2038 encryption_required = true;
2040 if (encryption_required && !req->do_encryption) {
2041 return smbd_smb2_request_error(req,
2042 NT_STATUS_ACCESS_DENIED);
2046 if (call->fileid_ofs != 0) {
2047 size_t needed = call->fileid_ofs + 16;
2048 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2049 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2050 uint64_t file_id_persistent;
2051 uint64_t file_id_volatile;
2052 struct files_struct *fsp;
2054 SMB_ASSERT(call->need_tcon);
2056 if (needed > body_size) {
2057 return smbd_smb2_request_error(req,
2058 NT_STATUS_INVALID_PARAMETER);
2061 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2062 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2064 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2065 if (fsp == NULL) {
2066 if (!call->allow_invalid_fileid) {
2067 return smbd_smb2_request_error(req,
2068 NT_STATUS_FILE_CLOSED);
2071 if (file_id_persistent != UINT64_MAX) {
2072 return smbd_smb2_request_error(req,
2073 NT_STATUS_FILE_CLOSED);
2075 if (file_id_volatile != UINT64_MAX) {
2076 return smbd_smb2_request_error(req,
2077 NT_STATUS_FILE_CLOSED);
2082 if (call->as_root) {
2083 SMB_ASSERT(call->fileid_ofs == 0);
2084 /* This call needs to be run as root */
2085 change_to_root_user();
2086 } else {
2087 SMB_ASSERT(call->need_tcon);
2090 switch (opcode) {
2091 case SMB2_OP_NEGPROT:
2093 START_PROFILE(smb2_negprot);
2094 return_value = smbd_smb2_request_process_negprot(req);
2095 END_PROFILE(smb2_negprot);
2097 break;
2099 case SMB2_OP_SESSSETUP:
2101 START_PROFILE(smb2_sesssetup);
2102 return_value = smbd_smb2_request_process_sesssetup(req);
2103 END_PROFILE(smb2_sesssetup);
2105 break;
2107 case SMB2_OP_LOGOFF:
2109 START_PROFILE(smb2_logoff);
2110 return_value = smbd_smb2_request_process_logoff(req);
2111 END_PROFILE(smb2_logoff);
2113 break;
2115 case SMB2_OP_TCON:
2117 START_PROFILE(smb2_tcon);
2118 return_value = smbd_smb2_request_process_tcon(req);
2119 END_PROFILE(smb2_tcon);
2121 break;
2123 case SMB2_OP_TDIS:
2125 START_PROFILE(smb2_tdis);
2126 return_value = smbd_smb2_request_process_tdis(req);
2127 END_PROFILE(smb2_tdis);
2129 break;
2131 case SMB2_OP_CREATE:
2133 START_PROFILE(smb2_create);
2134 return_value = smbd_smb2_request_process_create(req);
2135 END_PROFILE(smb2_create);
2137 break;
2139 case SMB2_OP_CLOSE:
2141 START_PROFILE(smb2_close);
2142 return_value = smbd_smb2_request_process_close(req);
2143 END_PROFILE(smb2_close);
2145 break;
2147 case SMB2_OP_FLUSH:
2149 START_PROFILE(smb2_flush);
2150 return_value = smbd_smb2_request_process_flush(req);
2151 END_PROFILE(smb2_flush);
2153 break;
2155 case SMB2_OP_READ:
2157 START_PROFILE(smb2_read);
2158 return_value = smbd_smb2_request_process_read(req);
2159 END_PROFILE(smb2_read);
2161 break;
2163 case SMB2_OP_WRITE:
2165 START_PROFILE(smb2_write);
2166 return_value = smbd_smb2_request_process_write(req);
2167 END_PROFILE(smb2_write);
2169 break;
2171 case SMB2_OP_LOCK:
2173 START_PROFILE(smb2_lock);
2174 return_value = smbd_smb2_request_process_lock(req);
2175 END_PROFILE(smb2_lock);
2177 break;
2179 case SMB2_OP_IOCTL:
2181 START_PROFILE(smb2_ioctl);
2182 return_value = smbd_smb2_request_process_ioctl(req);
2183 END_PROFILE(smb2_ioctl);
2185 break;
2187 case SMB2_OP_CANCEL:
2189 START_PROFILE(smb2_cancel);
2190 return_value = smbd_smb2_request_process_cancel(req);
2191 END_PROFILE(smb2_cancel);
2193 break;
2195 case SMB2_OP_KEEPALIVE:
2197 START_PROFILE(smb2_keepalive);
2198 return_value = smbd_smb2_request_process_keepalive(req);
2199 END_PROFILE(smb2_keepalive);
2201 break;
2203 case SMB2_OP_FIND:
2205 START_PROFILE(smb2_find);
2206 return_value = smbd_smb2_request_process_find(req);
2207 END_PROFILE(smb2_find);
2209 break;
2211 case SMB2_OP_NOTIFY:
2213 START_PROFILE(smb2_notify);
2214 return_value = smbd_smb2_request_process_notify(req);
2215 END_PROFILE(smb2_notify);
2217 break;
2219 case SMB2_OP_GETINFO:
2221 START_PROFILE(smb2_getinfo);
2222 return_value = smbd_smb2_request_process_getinfo(req);
2223 END_PROFILE(smb2_getinfo);
2225 break;
2227 case SMB2_OP_SETINFO:
2229 START_PROFILE(smb2_setinfo);
2230 return_value = smbd_smb2_request_process_setinfo(req);
2231 END_PROFILE(smb2_setinfo);
2233 break;
2235 case SMB2_OP_BREAK:
2237 START_PROFILE(smb2_break);
2238 return_value = smbd_smb2_request_process_break(req);
2239 END_PROFILE(smb2_break);
2241 break;
2243 default:
2244 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2245 break;
2247 return return_value;
2250 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2252 struct smbd_server_connection *sconn = req->sconn;
2253 struct smbXsrv_connection *conn = req->sconn->conn;
2254 int first_idx = 1;
2255 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2256 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2257 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2258 NTSTATUS status;
2260 req->subreq = NULL;
2261 TALLOC_FREE(req->async_te);
2263 if (req->do_encryption &&
2264 (firsttf->iov_len == 0) &&
2265 (req->first_key.length == 0) &&
2266 (req->session != NULL) &&
2267 (req->session->global->encryption_key.length != 0))
2269 DATA_BLOB encryption_key = req->session->global->encryption_key;
2270 uint8_t *tf;
2271 uint64_t session_id = req->session->global->session_wire_id;
2272 struct smbXsrv_session *x = req->session;
2273 uint64_t nonce_high;
2274 uint64_t nonce_low;
2276 nonce_high = x->nonce_high;
2277 nonce_low = x->nonce_low;
2279 x->nonce_low += 1;
2280 if (x->nonce_low == 0) {
2281 x->nonce_low += 1;
2282 x->nonce_high += 1;
2286 * We need to place the SMB2_TRANSFORM header before the
2287 * first SMB2 header
2291 * we need to remember the encryption key
2292 * and defer the signing/encryption until
2293 * we are sure that we do not change
2294 * the header again.
2296 req->first_key = data_blob_dup_talloc(req, encryption_key);
2297 if (req->first_key.data == NULL) {
2298 return NT_STATUS_NO_MEMORY;
2301 tf = talloc_zero_array(req->out.vector, uint8_t,
2302 SMB2_TF_HDR_SIZE);
2303 if (tf == NULL) {
2304 return NT_STATUS_NO_MEMORY;
2307 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2308 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2309 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2310 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2312 firsttf->iov_base = (void *)tf;
2313 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2316 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2317 (req->last_key.length > 0) &&
2318 (firsttf->iov_len == 0))
2320 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2321 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2324 * As we are sure the header of the last request in the
2325 * compound chain will not change, we can to sign here
2326 * with the last signing key we remembered.
2328 status = smb2_signing_sign_pdu(req->last_key,
2329 conn->protocol,
2330 lasthdr,
2331 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2332 if (!NT_STATUS_IS_OK(status)) {
2333 return status;
2336 data_blob_clear_free(&req->last_key);
2338 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2340 if (req->current_idx < req->out.vector_count) {
2342 * We must process the remaining compound
2343 * SMB2 requests before any new incoming SMB2
2344 * requests. This is because incoming SMB2
2345 * requests may include a cancel for a
2346 * compound request we haven't processed
2347 * yet.
2349 struct tevent_immediate *im = tevent_create_immediate(req);
2350 if (!im) {
2351 return NT_STATUS_NO_MEMORY;
2354 if (req->do_signing && firsttf->iov_len == 0) {
2355 struct smbXsrv_session *x = req->session;
2356 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2359 * we need to remember the signing key
2360 * and defer the signing until
2361 * we are sure that we do not change
2362 * the header again.
2364 req->last_key = data_blob_dup_talloc(req, signing_key);
2365 if (req->last_key.data == NULL) {
2366 return NT_STATUS_NO_MEMORY;
2370 tevent_schedule_immediate(im,
2371 req->sconn->ev_ctx,
2372 smbd_smb2_request_dispatch_immediate,
2373 req);
2374 return NT_STATUS_OK;
2377 if (req->compound_related) {
2378 req->compound_related = false;
2381 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2383 /* Set credit for these operations (zero credits if this
2384 is a final reply for an async operation). */
2385 smb2_calculate_credits(req, req);
2388 * now check if we need to sign the current response
2390 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2391 status = smb2_signing_encrypt_pdu(req->first_key,
2392 conn->protocol,
2393 firsttf,
2394 req->out.vector_count - first_idx);
2395 if (!NT_STATUS_IS_OK(status)) {
2396 return status;
2398 } else if (req->do_signing) {
2399 struct smbXsrv_session *x = req->session;
2400 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2402 status = smb2_signing_sign_pdu(signing_key,
2403 conn->protocol,
2404 outhdr,
2405 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2406 if (!NT_STATUS_IS_OK(status)) {
2407 return status;
2410 data_blob_clear_free(&req->first_key);
2412 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2413 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2414 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2415 /* Dynamic part is NULL. Chop it off,
2416 We're going to send it via sendfile. */
2417 req->out.vector_count -= 1;
2421 * We're done with this request -
2422 * move it off the "being processed" queue.
2424 DLIST_REMOVE(req->sconn->smb2.requests, req);
2426 req->queue_entry.mem_ctx = req;
2427 req->queue_entry.vector = req->out.vector;
2428 req->queue_entry.count = req->out.vector_count;
2429 DLIST_ADD_END(req->sconn->smb2.send_queue, &req->queue_entry, NULL);
2430 req->sconn->smb2.send_queue_len++;
2432 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2433 if (!NT_STATUS_IS_OK(status)) {
2434 return status;
2437 return NT_STATUS_OK;
2440 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2442 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2443 struct tevent_immediate *im,
2444 void *private_data)
2446 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2447 struct smbd_smb2_request);
2448 struct smbd_server_connection *sconn = req->sconn;
2449 NTSTATUS status;
2451 TALLOC_FREE(im);
2453 if (DEBUGLEVEL >= 10) {
2454 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2455 req->current_idx, req->in.vector_count));
2456 print_req_vectors(req);
2459 status = smbd_smb2_request_dispatch(req);
2460 if (!NT_STATUS_IS_OK(status)) {
2461 smbd_server_connection_terminate(sconn, nt_errstr(status));
2462 return;
2465 status = smbd_smb2_request_next_incoming(sconn);
2466 if (!NT_STATUS_IS_OK(status)) {
2467 smbd_server_connection_terminate(sconn, nt_errstr(status));
2468 return;
2472 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2473 NTSTATUS status,
2474 DATA_BLOB body, DATA_BLOB *dyn,
2475 const char *location)
2477 uint8_t *outhdr;
2478 struct iovec *outbody_v;
2479 struct iovec *outdyn_v;
2480 uint32_t next_command_ofs;
2482 DEBUG(10,("smbd_smb2_request_done_ex: "
2483 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2484 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2485 dyn ? "yes": "no",
2486 (unsigned int)(dyn ? dyn->length : 0),
2487 location));
2489 if (body.length < 2) {
2490 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2493 if ((body.length % 2) != 0) {
2494 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2497 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2498 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2499 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2501 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2502 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2504 outbody_v->iov_base = (void *)body.data;
2505 outbody_v->iov_len = body.length;
2507 if (dyn) {
2508 outdyn_v->iov_base = (void *)dyn->data;
2509 outdyn_v->iov_len = dyn->length;
2510 } else {
2511 outdyn_v->iov_base = NULL;
2512 outdyn_v->iov_len = 0;
2515 /* see if we need to recalculate the offset to the next response */
2516 if (next_command_ofs > 0) {
2517 next_command_ofs = SMB2_HDR_BODY;
2518 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2519 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2522 if ((next_command_ofs % 8) != 0) {
2523 size_t pad_size = 8 - (next_command_ofs % 8);
2524 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2526 * if the dyn buffer is empty
2527 * we can use it to add padding
2529 uint8_t *pad;
2531 pad = talloc_zero_array(req->out.vector,
2532 uint8_t, pad_size);
2533 if (pad == NULL) {
2534 return smbd_smb2_request_error(req,
2535 NT_STATUS_NO_MEMORY);
2538 outdyn_v->iov_base = (void *)pad;
2539 outdyn_v->iov_len = pad_size;
2540 } else {
2542 * For now we copy the dynamic buffer
2543 * and add the padding to the new buffer
2545 size_t old_size;
2546 uint8_t *old_dyn;
2547 size_t new_size;
2548 uint8_t *new_dyn;
2550 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2551 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2553 new_size = old_size + pad_size;
2554 new_dyn = talloc_zero_array(req->out.vector,
2555 uint8_t, new_size);
2556 if (new_dyn == NULL) {
2557 return smbd_smb2_request_error(req,
2558 NT_STATUS_NO_MEMORY);
2561 memcpy(new_dyn, old_dyn, old_size);
2562 memset(new_dyn + old_size, 0, pad_size);
2564 outdyn_v->iov_base = (void *)new_dyn;
2565 outdyn_v->iov_len = new_size;
2567 next_command_ofs += pad_size;
2570 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2572 return smbd_smb2_request_reply(req);
2575 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2576 NTSTATUS status,
2577 DATA_BLOB *info,
2578 const char *location)
2580 DATA_BLOB body;
2581 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2582 size_t unread_bytes = smbd_smb2_unread_bytes(req);
2584 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2585 req->current_idx, nt_errstr(status), info ? " +info" : "",
2586 location));
2588 if (unread_bytes) {
2589 /* Recvfile error. Drain incoming socket. */
2590 size_t ret;
2592 errno = 0;
2593 ret = drain_socket(req->sconn->sock, unread_bytes);
2594 if (ret != unread_bytes) {
2595 NTSTATUS error;
2597 if (errno == 0) {
2598 error = NT_STATUS_IO_DEVICE_ERROR;
2599 } else {
2600 error = map_nt_error_from_unix_common(errno);
2603 DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: "
2604 "ret[%u] errno[%d] => %s\n",
2605 (unsigned)unread_bytes,
2606 (unsigned)ret, errno, nt_errstr(error)));
2607 return error;
2611 body.data = outhdr + SMB2_HDR_BODY;
2612 body.length = 8;
2613 SSVAL(body.data, 0, 9);
2615 if (info) {
2616 SIVAL(body.data, 0x04, info->length);
2617 } else {
2618 /* Allocated size of req->out.vector[i].iov_base
2619 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2620 * 1 byte without having to do an alloc.
2622 info = talloc_zero_array(req->out.vector,
2623 DATA_BLOB,
2625 if (!info) {
2626 return NT_STATUS_NO_MEMORY;
2628 info->data = ((uint8_t *)outhdr) +
2629 OUTVEC_ALLOC_SIZE - 1;
2630 info->length = 1;
2631 SCVAL(info->data, 0, 0);
2635 * Note: Even if there is an error, continue to process the request.
2636 * per MS-SMB2.
2639 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2643 struct smbd_smb2_send_oplock_break_state {
2644 struct smbd_server_connection *sconn;
2645 struct smbd_smb2_send_queue queue_entry;
2646 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18];
2647 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2650 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2651 struct smbXsrv_session *session,
2652 struct smbXsrv_tcon *tcon,
2653 struct smbXsrv_open *op,
2654 uint8_t oplock_level)
2656 struct smbd_smb2_send_oplock_break_state *state;
2657 struct smbXsrv_connection *conn = sconn->conn;
2658 uint8_t *tf;
2659 size_t tf_len;
2660 uint8_t *hdr;
2661 uint8_t *body;
2662 size_t body_len;
2663 uint8_t *dyn;
2664 size_t dyn_len;
2665 bool do_encryption = session->global->encryption_required;
2666 uint64_t nonce_high = 0;
2667 uint64_t nonce_low = 0;
2668 NTSTATUS status;
2670 if (tcon->global->encryption_required) {
2671 do_encryption = true;
2674 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2675 if (state == NULL) {
2676 return NT_STATUS_NO_MEMORY;
2678 state->sconn = sconn;
2680 tf = state->buf + NBT_HDR_SIZE;
2681 tf_len = SMB2_TF_HDR_SIZE;
2682 hdr = tf + tf_len;
2683 body = hdr + SMB2_HDR_BODY;
2684 body_len = 0x18;
2685 dyn = body + body_len;
2686 dyn_len = 0;
2688 if (do_encryption) {
2689 nonce_high = session->nonce_high;
2690 nonce_low = session->nonce_low;
2692 session->nonce_low += 1;
2693 if (session->nonce_low == 0) {
2694 session->nonce_low += 1;
2695 session->nonce_high += 1;
2699 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2700 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2701 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2702 SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
2704 SIVAL(hdr, 0, SMB2_MAGIC);
2705 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2706 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2707 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2708 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2709 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2710 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2711 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2712 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2713 SIVAL(hdr, SMB2_HDR_PID, 0);
2714 SIVAL(hdr, SMB2_HDR_TID, 0);
2715 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2716 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2718 SSVAL(body, 0x00, body_len);
2720 SCVAL(body, 0x02, oplock_level);
2721 SCVAL(body, 0x03, 0); /* reserved */
2722 SIVAL(body, 0x04, 0); /* reserved */
2723 SBVAL(body, 0x08, op->global->open_persistent_id);
2724 SBVAL(body, 0x10, op->global->open_volatile_id);
2726 state->vector[0].iov_base = (void *)state->buf;
2727 state->vector[0].iov_len = NBT_HDR_SIZE;
2729 if (do_encryption) {
2730 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
2731 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
2732 } else {
2733 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
2734 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
2737 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
2738 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
2740 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
2741 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = body_len;
2743 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
2744 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_len;
2746 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2748 if (do_encryption) {
2749 DATA_BLOB encryption_key = session->global->encryption_key;
2751 status = smb2_signing_encrypt_pdu(encryption_key,
2752 conn->protocol,
2753 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2754 SMBD_SMB2_NUM_IOV_PER_REQ);
2755 if (!NT_STATUS_IS_OK(status)) {
2756 return status;
2760 state->queue_entry.mem_ctx = state;
2761 state->queue_entry.vector = state->vector;
2762 state->queue_entry.count = ARRAY_SIZE(state->vector);
2763 DLIST_ADD_END(state->sconn->smb2.send_queue, &state->queue_entry, NULL);
2764 state->sconn->smb2.send_queue_len++;
2766 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2767 if (!NT_STATUS_IS_OK(status)) {
2768 return status;
2771 return NT_STATUS_OK;
2774 static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
2776 if (smb2_req->do_signing) {
2777 return 0;
2779 if (smb2_req->do_encryption) {
2780 return 0;
2782 return (size_t)lp_min_receive_file_size();
2785 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
2787 uint32_t flags;
2789 if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
2790 /* Transform header. Cannot recvfile. */
2791 return false;
2793 if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
2794 /* Not SMB2. Normal error path will cope. */
2795 return false;
2797 if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
2798 /* Not SMB2. Normal error path will cope. */
2799 return false;
2801 if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
2802 /* Needs to be a WRITE. */
2803 return false;
2805 if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
2806 /* Chained. Cannot recvfile. */
2807 return false;
2809 flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
2810 if (flags & SMB2_HDR_FLAG_CHAINED) {
2811 /* Chained. Cannot recvfile. */
2812 return false;
2814 if (flags & SMB2_HDR_FLAG_SIGNED) {
2815 /* Signed. Cannot recvfile. */
2816 return false;
2819 DEBUG(10,("Doing recvfile write len = %u\n",
2820 (unsigned int)(state->pktlen -
2821 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
2823 return true;
2826 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2828 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
2829 size_t max_send_queue_len;
2830 size_t cur_send_queue_len;
2832 if (state->req != NULL) {
2834 * if there is already a tstream_readv_pdu
2835 * pending, we are done.
2837 return NT_STATUS_OK;
2840 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2841 cur_send_queue_len = sconn->smb2.send_queue_len;
2843 if (cur_send_queue_len > max_send_queue_len) {
2845 * if we have a lot of requests to send,
2846 * we wait until they are on the wire until we
2847 * ask for the next request.
2849 return NT_STATUS_OK;
2852 /* ask for the next request */
2853 ZERO_STRUCTP(state);
2854 state->req = smbd_smb2_request_allocate(sconn);
2855 if (state->req == NULL) {
2856 return NT_STATUS_NO_MEMORY;
2858 state->req->sconn = sconn;
2859 state->min_recv_size = get_min_receive_file_size(state->req);
2861 TEVENT_FD_READABLE(sconn->smb2.fde);
2863 return NT_STATUS_OK;
2866 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2867 uint8_t *inbuf, size_t size)
2869 NTSTATUS status;
2870 struct smbd_smb2_request *req = NULL;
2872 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2873 (unsigned int)size));
2875 status = smbd_initialize_smb2(sconn);
2876 if (!NT_STATUS_IS_OK(status)) {
2877 smbd_server_connection_terminate(sconn, nt_errstr(status));
2878 return;
2881 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2882 if (!NT_STATUS_IS_OK(status)) {
2883 smbd_server_connection_terminate(sconn, nt_errstr(status));
2884 return;
2887 status = smbd_smb2_request_validate(req);
2888 if (!NT_STATUS_IS_OK(status)) {
2889 smbd_server_connection_terminate(sconn, nt_errstr(status));
2890 return;
2893 status = smbd_smb2_request_setup_out(req);
2894 if (!NT_STATUS_IS_OK(status)) {
2895 smbd_server_connection_terminate(sconn, nt_errstr(status));
2896 return;
2899 status = smbd_smb2_request_dispatch(req);
2900 if (!NT_STATUS_IS_OK(status)) {
2901 smbd_server_connection_terminate(sconn, nt_errstr(status));
2902 return;
2905 status = smbd_smb2_request_next_incoming(sconn);
2906 if (!NT_STATUS_IS_OK(status)) {
2907 smbd_server_connection_terminate(sconn, nt_errstr(status));
2908 return;
2911 sconn->num_requests++;
2914 static int socket_error_from_errno(int ret,
2915 int sys_errno,
2916 bool *retry)
2918 *retry = false;
2920 if (ret >= 0) {
2921 return 0;
2924 if (ret != -1) {
2925 return EIO;
2928 if (sys_errno == 0) {
2929 return EIO;
2932 if (sys_errno == EINTR) {
2933 *retry = true;
2934 return sys_errno;
2937 if (sys_errno == EINPROGRESS) {
2938 *retry = true;
2939 return sys_errno;
2942 if (sys_errno == EAGAIN) {
2943 *retry = true;
2944 return sys_errno;
2947 /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
2948 if (sys_errno == ENOMEM) {
2949 *retry = true;
2950 return sys_errno;
2953 #ifdef EWOULDBLOCK
2954 if (sys_errno == EWOULDBLOCK) {
2955 *retry = true;
2956 return sys_errno;
2958 #endif
2960 return sys_errno;
2963 static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn)
2965 int ret;
2966 int err;
2967 bool retry;
2969 if (sconn->smb2.send_queue == NULL) {
2970 TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
2971 return NT_STATUS_OK;
2974 while (sconn->smb2.send_queue != NULL) {
2975 struct smbd_smb2_send_queue *e = sconn->smb2.send_queue;
2977 ret = writev(sconn->sock, e->vector, e->count);
2978 if (ret == 0) {
2979 /* propagate end of file */
2980 return NT_STATUS_INTERNAL_ERROR;
2982 err = socket_error_from_errno(ret, errno, &retry);
2983 if (retry) {
2984 /* retry later */
2985 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
2986 return NT_STATUS_OK;
2988 if (err != 0) {
2989 return map_nt_error_from_unix_common(err);
2991 while (ret > 0) {
2992 if (ret < e->vector[0].iov_len) {
2993 uint8_t *base;
2994 base = (uint8_t *)e->vector[0].iov_base;
2995 base += ret;
2996 e->vector[0].iov_base = (void *)base;
2997 e->vector[0].iov_len -= ret;
2998 break;
3000 ret -= e->vector[0].iov_len;
3001 e->vector += 1;
3002 e->count -= 1;
3006 * there're maybe some empty vectors at the end
3007 * which we need to skip, otherwise we would get
3008 * ret == 0 from the readv() call and return EPIPE
3010 while (e->count > 0) {
3011 if (e->vector[0].iov_len > 0) {
3012 break;
3014 e->vector += 1;
3015 e->count -= 1;
3018 if (e->count > 0) {
3019 /* we have more to write */
3020 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
3021 return NT_STATUS_OK;
3024 sconn->smb2.send_queue_len--;
3025 DLIST_REMOVE(sconn->smb2.send_queue, e);
3026 talloc_free(e->mem_ctx);
3029 return NT_STATUS_OK;
3032 static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn,
3033 uint16_t fde_flags)
3035 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
3036 struct smbd_smb2_request *req = NULL;
3037 size_t min_recvfile_size = UINT32_MAX;
3038 int ret;
3039 int err;
3040 bool retry;
3041 NTSTATUS status;
3042 NTTIME now;
3044 if (fde_flags & TEVENT_FD_WRITE) {
3045 status = smbd_smb2_flush_send_queue(sconn);
3046 if (!NT_STATUS_IS_OK(status)) {
3047 return status;
3051 if (!(fde_flags & TEVENT_FD_READ)) {
3052 return NT_STATUS_OK;
3055 if (state->req == NULL) {
3056 TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
3057 return NT_STATUS_OK;
3060 again:
3061 if (!state->hdr.done) {
3062 state->hdr.done = true;
3064 state->vector.iov_base = (void *)state->hdr.nbt;
3065 state->vector.iov_len = NBT_HDR_SIZE;
3068 ret = readv(sconn->sock, &state->vector, 1);
3069 if (ret == 0) {
3070 /* propagate end of file */
3071 return NT_STATUS_END_OF_FILE;
3073 err = socket_error_from_errno(ret, errno, &retry);
3074 if (retry) {
3075 /* retry later */
3076 TEVENT_FD_READABLE(sconn->smb2.fde);
3077 return NT_STATUS_OK;
3079 if (err != 0) {
3080 return map_nt_error_from_unix_common(err);
3083 if (ret < state->vector.iov_len) {
3084 uint8_t *base;
3085 base = (uint8_t *)state->vector.iov_base;
3086 base += ret;
3087 state->vector.iov_base = (void *)base;
3088 state->vector.iov_len -= ret;
3089 /* we have more to read */
3090 TEVENT_FD_READABLE(sconn->smb2.fde);
3091 return NT_STATUS_OK;
3094 if (state->pktlen > 0) {
3095 if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
3097 * Not a possible receivefile write.
3098 * Read the rest of the data.
3100 state->doing_receivefile = false;
3101 state->vector.iov_base = (void *)(state->pktbuf +
3102 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3103 state->vector.iov_len = (state->pktlen -
3104 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3105 goto again;
3109 * Either this is a receivefile write so we've
3110 * done a short read, or if not we have all the data.
3112 goto got_full;
3116 * Now we analyze the NBT header
3118 state->pktlen = smb2_len(state->hdr.nbt);
3119 if (state->pktlen == 0) {
3120 goto got_full;
3123 state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
3124 if (state->pktbuf == NULL) {
3125 return NT_STATUS_NO_MEMORY;
3128 state->vector.iov_base = (void *)state->pktbuf;
3130 if (state->min_recv_size != 0) {
3131 min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3132 min_recvfile_size += state->min_recv_size;
3135 if (state->pktlen > min_recvfile_size) {
3137 * Might be a receivefile write. Read the SMB2 HEADER +
3138 * SMB2_WRITE header first. Set 'doing_receivefile'
3139 * as we're *attempting* receivefile write. If this
3140 * turns out not to be a SMB2_WRITE request or otherwise
3141 * not suitable then we'll just read the rest of the data
3142 * the next time this function is called.
3144 state->vector.iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3145 state->doing_receivefile = true;
3146 } else {
3147 state->vector.iov_len = state->pktlen;
3150 goto again;
3152 got_full:
3154 if (state->hdr.nbt[0] != 0x00) {
3155 DEBUG(1,("ignore NBT[0x%02X] msg\n",
3156 state->hdr.nbt[0]));
3158 req = state->req;
3159 ZERO_STRUCTP(state);
3160 state->req = req;
3161 state->min_recv_size = get_min_receive_file_size(state->req);
3162 req = NULL;
3163 goto again;
3166 req = state->req;
3167 state->req = NULL;
3169 req->request_time = timeval_current();
3170 now = timeval_to_nttime(&req->request_time);
3172 status = smbd_smb2_inbuf_parse_compound(req->sconn->conn,
3173 now,
3174 state->pktbuf,
3175 state->pktlen,
3176 req,
3177 &req->in.vector,
3178 &req->in.vector_count);
3179 if (!NT_STATUS_IS_OK(status)) {
3180 return status;
3183 if (state->doing_receivefile) {
3184 req->smb1req = talloc_zero(req, struct smb_request);
3185 if (req->smb1req == NULL) {
3186 return NT_STATUS_NO_MEMORY;
3188 req->smb1req->unread_bytes =
3189 state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3192 ZERO_STRUCTP(state);
3194 req->current_idx = 1;
3196 DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n",
3197 req->current_idx, req->in.vector_count));
3199 status = smbd_smb2_request_validate(req);
3200 if (!NT_STATUS_IS_OK(status)) {
3201 return status;
3204 status = smbd_smb2_request_setup_out(req);
3205 if (!NT_STATUS_IS_OK(status)) {
3206 return status;
3209 status = smbd_smb2_request_dispatch(req);
3210 if (!NT_STATUS_IS_OK(status)) {
3211 return status;
3214 sconn->num_requests++;
3216 /* The timeout_processing function isn't run nearly
3217 often enough to implement 'max log size' without
3218 overrunning the size of the file by many megabytes.
3219 This is especially true if we are running at debug
3220 level 10. Checking every 50 SMB2s is a nice
3221 tradeoff of performance vs log file size overrun. */
3223 if ((sconn->num_requests % 50) == 0 &&
3224 need_to_check_log_size()) {
3225 change_to_root_user();
3226 check_log_size();
3229 status = smbd_smb2_request_next_incoming(sconn);
3230 if (!NT_STATUS_IS_OK(status)) {
3231 return status;
3234 return NT_STATUS_OK;
3237 static void smbd_smb2_connection_handler(struct tevent_context *ev,
3238 struct tevent_fd *fde,
3239 uint16_t flags,
3240 void *private_data)
3242 struct smbd_server_connection *sconn =
3243 talloc_get_type_abort(private_data,
3244 struct smbd_server_connection);
3245 NTSTATUS status;
3247 status = smbd_smb2_io_handler(sconn, flags);
3248 if (!NT_STATUS_IS_OK(status)) {
3249 smbd_server_connection_terminate(sconn, nt_errstr(status));
3250 return;