s3:smb2_server: use tevent_req_notify_callback() in smbd_smb2_request_pending_queue()
[Samba.git] / source3 / smbd / smb2_server.c
blobb179a0b0273ba57cddbd7ea3ba0b6393a36810c7
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)) {
1256 * This is a performance optimization,
1257 * it avoids one tevent_loop iteration,
1258 * which means we avoid one
1259 * talloc_stackframe_pool/talloc_free pair.
1261 tevent_req_notify_callback(subreq);
1262 return NT_STATUS_OK;
1265 req->subreq = subreq;
1266 subreq = NULL;
1268 if (req->async_te) {
1269 /* We're already async. */
1270 return NT_STATUS_OK;
1273 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1274 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1275 if (flags & SMB2_HDR_FLAG_ASYNC) {
1276 /* We're already async. */
1277 return NT_STATUS_OK;
1280 if (req->in.vector_count > req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
1282 * We're trying to go async in a compound
1283 * request chain.
1284 * This is only allowed for opens that
1285 * cause an oplock break, otherwise it
1286 * is not allowed. See [MS-SMB2].pdf
1287 * note <194> on Section 3.3.5.2.7.
1289 const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1291 if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_CREATE) {
1293 * Cancel the outstanding request.
1295 bool ok = tevent_req_cancel(req->subreq);
1296 if (ok) {
1297 return NT_STATUS_OK;
1299 TALLOC_FREE(req->subreq);
1300 return smbd_smb2_request_error(req,
1301 NT_STATUS_INTERNAL_ERROR);
1305 if (DEBUGLEVEL >= 10) {
1306 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
1307 (unsigned int)req->current_idx );
1308 print_req_vectors(req);
1311 if (req->current_idx > 1) {
1313 * We're going async in a compound
1314 * chain after the first request has
1315 * already been processed. Send an
1316 * interim response containing the
1317 * set of replies already generated.
1319 int idx = req->current_idx;
1321 status = smb2_send_async_interim_response(req);
1322 if (!NT_STATUS_IS_OK(status)) {
1323 return status;
1325 data_blob_clear_free(&req->first_key);
1327 req->current_idx = 1;
1330 * Re-arrange the in.vectors to remove what
1331 * we just sent.
1333 memmove(&req->in.vector[1],
1334 &req->in.vector[idx],
1335 sizeof(req->in.vector[0])*(req->in.vector_count - idx));
1336 req->in.vector_count = 1 + (req->in.vector_count - idx);
1338 /* Re-arrange the out.vectors to match. */
1339 memmove(&req->out.vector[1],
1340 &req->out.vector[idx],
1341 sizeof(req->out.vector[0])*(req->out.vector_count - idx));
1342 req->out.vector_count = 1 + (req->out.vector_count - idx);
1344 if (req->in.vector_count == 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
1346 * We only have one remaining request as
1347 * we've processed everything else.
1348 * This is no longer a compound request.
1350 req->compound_related = false;
1351 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1352 flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
1353 SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
1356 data_blob_clear_free(&req->last_key);
1358 defer_endtime = timeval_current_ofs_usec(defer_time);
1359 req->async_te = tevent_add_timer(req->sconn->ev_ctx,
1360 req, defer_endtime,
1361 smbd_smb2_request_pending_timer,
1362 req);
1363 if (req->async_te == NULL) {
1364 return NT_STATUS_NO_MEMORY;
1367 return NT_STATUS_OK;
1370 static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
1371 struct tevent_timer *te,
1372 struct timeval current_time,
1373 void *private_data)
1375 struct smbd_smb2_request *req =
1376 talloc_get_type_abort(private_data,
1377 struct smbd_smb2_request);
1378 struct smbd_server_connection *sconn = req->sconn;
1379 struct smbd_smb2_request_pending_state *state = NULL;
1380 uint8_t *outhdr = NULL;
1381 const uint8_t *inhdr = NULL;
1382 uint8_t *tf = NULL;
1383 size_t tf_len = 0;
1384 uint8_t *hdr = NULL;
1385 uint8_t *body = NULL;
1386 uint8_t *dyn = NULL;
1387 uint32_t flags = 0;
1388 uint64_t session_id = 0;
1389 uint64_t message_id = 0;
1390 uint64_t nonce_high = 0;
1391 uint64_t nonce_low = 0;
1392 uint64_t async_id = 0;
1393 NTSTATUS status;
1395 TALLOC_FREE(req->async_te);
1397 /* Ensure our final reply matches the interim one. */
1398 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1399 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
1400 flags = IVAL(outhdr, SMB2_HDR_FLAGS);
1401 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1402 session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1404 async_id = message_id; /* keep it simple for now... */
1406 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1407 SBVAL(outhdr, SMB2_HDR_ASYNC_ID, async_id);
1409 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
1410 "going async\n",
1411 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1412 (unsigned long long)async_id ));
1415 * What we send is identical to a smbd_smb2_request_error
1416 * packet with an error status of STATUS_PENDING. Make use
1417 * of this fact sometime when refactoring. JRA.
1420 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
1421 if (state == NULL) {
1422 smbd_server_connection_terminate(req->sconn,
1423 nt_errstr(NT_STATUS_NO_MEMORY));
1424 return;
1426 state->sconn = req->sconn;
1428 tf = state->buf + NBT_HDR_SIZE;
1429 tf_len = SMB2_TF_HDR_SIZE;
1431 hdr = tf + SMB2_TF_HDR_SIZE;
1432 body = hdr + SMB2_HDR_BODY;
1433 dyn = body + 8;
1435 if (req->do_encryption) {
1436 struct smbXsrv_session *x = req->session;
1438 nonce_high = x->nonce_high;
1439 nonce_low = x->nonce_low;
1441 x->nonce_low += 1;
1442 if (x->nonce_low == 0) {
1443 x->nonce_low += 1;
1444 x->nonce_high += 1;
1448 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
1449 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
1450 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
1451 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
1453 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
1454 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1455 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1456 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
1457 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(outhdr, SMB2_HDR_OPCODE));
1459 SIVAL(hdr, SMB2_HDR_FLAGS, flags);
1460 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1461 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
1462 SBVAL(hdr, SMB2_HDR_PID, async_id);
1463 SBVAL(hdr, SMB2_HDR_SESSION_ID,
1464 BVAL(outhdr, SMB2_HDR_SESSION_ID));
1465 memcpy(hdr+SMB2_HDR_SIGNATURE,
1466 outhdr+SMB2_HDR_SIGNATURE, 16);
1468 SSVAL(body, 0x00, 0x08 + 1);
1470 SCVAL(body, 0x02, 0);
1471 SCVAL(body, 0x03, 0);
1472 SIVAL(body, 0x04, 0);
1473 /* Match W2K8R2... */
1474 SCVAL(dyn, 0x00, 0x21);
1476 state->vector[0].iov_base = (void *)state->buf;
1477 state->vector[0].iov_len = NBT_HDR_SIZE;
1479 if (req->do_encryption) {
1480 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
1481 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
1482 } else {
1483 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
1484 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
1487 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
1488 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
1490 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
1491 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = 8;
1493 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
1494 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = 1;
1496 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
1498 /* Ensure we correctly go through crediting. Grant
1499 the credits now, and zero credits on the final
1500 response. */
1501 smb2_set_operation_credit(req->sconn,
1502 SMBD_SMB2_IN_HDR_IOV(req),
1503 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS]);
1505 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
1507 if (DEBUGLVL(10)) {
1508 int i;
1510 for (i = 0; i < ARRAY_SIZE(state->vector); i++) {
1511 dbgtext("\tstate->vector[%u/%u].iov_len = %u\n",
1512 (unsigned int)i,
1513 (unsigned int)ARRAY_SIZE(state->vector),
1514 (unsigned int)state->vector[i].iov_len);
1518 if (req->do_encryption) {
1519 struct smbXsrv_session *x = req->session;
1520 struct smbXsrv_connection *conn = x->connection;
1521 DATA_BLOB encryption_key = x->global->encryption_key;
1523 status = smb2_signing_encrypt_pdu(encryption_key,
1524 conn->protocol,
1525 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
1526 SMBD_SMB2_NUM_IOV_PER_REQ);
1527 if (!NT_STATUS_IS_OK(status)) {
1528 smbd_server_connection_terminate(req->sconn,
1529 nt_errstr(status));
1530 return;
1532 } else if (req->do_signing) {
1533 struct smbXsrv_session *x = req->session;
1534 struct smbXsrv_connection *conn = x->connection;
1535 DATA_BLOB signing_key = x->global->channels[0].signing_key;
1537 status = smb2_signing_sign_pdu(signing_key,
1538 conn->protocol,
1539 &state->vector[1+SMBD_SMB2_HDR_IOV_OFS],
1540 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1541 if (!NT_STATUS_IS_OK(status)) {
1542 smbd_server_connection_terminate(req->sconn,
1543 nt_errstr(status));
1544 return;
1548 state->queue_entry.mem_ctx = state;
1549 state->queue_entry.vector = state->vector;
1550 state->queue_entry.count = ARRAY_SIZE(state->vector);
1551 DLIST_ADD_END(sconn->smb2.send_queue, &state->queue_entry, NULL);
1552 sconn->smb2.send_queue_len++;
1554 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
1555 if (!NT_STATUS_IS_OK(status)) {
1556 smbd_server_connection_terminate(sconn,
1557 nt_errstr(status));
1558 return;
1562 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
1564 struct smbd_server_connection *sconn = req->sconn;
1565 struct smbd_smb2_request *cur;
1566 const uint8_t *inhdr;
1567 uint32_t flags;
1568 uint64_t search_message_id;
1569 uint64_t search_async_id;
1570 uint64_t found_id;
1572 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1574 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1575 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1576 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
1579 * we don't need the request anymore
1580 * cancel requests never have a response
1582 DLIST_REMOVE(req->sconn->smb2.requests, req);
1583 TALLOC_FREE(req);
1585 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
1586 const uint8_t *outhdr;
1587 uint64_t message_id;
1588 uint64_t async_id;
1590 if (cur->compound_related) {
1592 * Never cancel anything in a compound request.
1593 * Way too hard to deal with the result.
1595 continue;
1598 outhdr = SMBD_SMB2_OUT_HDR_PTR(cur);
1600 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
1601 async_id = BVAL(outhdr, SMB2_HDR_PID);
1603 if (flags & SMB2_HDR_FLAG_ASYNC) {
1604 if (search_async_id == async_id) {
1605 found_id = async_id;
1606 break;
1608 } else {
1609 if (search_message_id == message_id) {
1610 found_id = message_id;
1611 break;
1616 if (cur && cur->subreq) {
1617 inhdr = SMBD_SMB2_IN_HDR_PTR(cur);
1618 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
1619 "cancel opcode[%s] mid %llu\n",
1620 smb2_opcode_name(SVAL(inhdr, SMB2_HDR_OPCODE)),
1621 (unsigned long long)found_id ));
1622 tevent_req_cancel(cur->subreq);
1625 return NT_STATUS_OK;
1628 /*************************************************************
1629 Ensure an incoming tid is a valid one for us to access.
1630 Change to the associated uid credentials and chdir to the
1631 valid tid directory.
1632 *************************************************************/
1634 static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
1636 const uint8_t *inhdr;
1637 uint32_t in_flags;
1638 uint32_t in_tid;
1639 struct smbXsrv_tcon *tcon;
1640 NTSTATUS status;
1641 NTTIME now = timeval_to_nttime(&req->request_time);
1643 req->tcon = NULL;
1645 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1647 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1648 in_tid = IVAL(inhdr, SMB2_HDR_TID);
1650 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1651 in_tid = req->last_tid;
1654 req->last_tid = 0;
1656 status = smb2srv_tcon_lookup(req->session,
1657 in_tid, now, &tcon);
1658 if (!NT_STATUS_IS_OK(status)) {
1659 return status;
1662 if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
1663 return NT_STATUS_ACCESS_DENIED;
1666 /* should we pass FLAG_CASELESS_PATHNAMES here? */
1667 if (!set_current_service(tcon->compat, 0, true)) {
1668 return NT_STATUS_ACCESS_DENIED;
1671 req->tcon = tcon;
1672 req->last_tid = in_tid;
1674 return NT_STATUS_OK;
1677 /*************************************************************
1678 Ensure an incoming session_id is a valid one for us to access.
1679 *************************************************************/
1681 static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
1683 const uint8_t *inhdr;
1684 uint32_t in_flags;
1685 uint16_t in_opcode;
1686 uint64_t in_session_id;
1687 struct smbXsrv_session *session = NULL;
1688 struct auth_session_info *session_info;
1689 NTSTATUS status;
1690 NTTIME now = timeval_to_nttime(&req->request_time);
1692 req->session = NULL;
1693 req->tcon = NULL;
1695 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1697 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1698 in_opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1699 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
1701 if (in_flags & SMB2_HDR_FLAG_CHAINED) {
1702 in_session_id = req->last_session_id;
1705 req->last_session_id = 0;
1707 /* lookup an existing session */
1708 status = smb2srv_session_lookup(req->sconn->conn,
1709 in_session_id, now,
1710 &session);
1711 if (session) {
1712 req->session = session;
1713 req->last_session_id = in_session_id;
1715 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1716 switch (in_opcode) {
1717 case SMB2_OP_SESSSETUP:
1718 status = NT_STATUS_OK;
1719 break;
1720 default:
1721 break;
1724 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1725 switch (in_opcode) {
1726 case SMB2_OP_TCON:
1727 case SMB2_OP_CREATE:
1728 case SMB2_OP_GETINFO:
1729 case SMB2_OP_SETINFO:
1730 return NT_STATUS_INVALID_HANDLE;
1731 default:
1733 * Notice the check for
1734 * (session_info == NULL)
1735 * below.
1737 status = NT_STATUS_OK;
1738 break;
1741 if (!NT_STATUS_IS_OK(status)) {
1742 return status;
1745 session_info = session->global->auth_session_info;
1746 if (session_info == NULL) {
1747 return NT_STATUS_INVALID_HANDLE;
1750 set_current_user_info(session_info->unix_info->sanitized_username,
1751 session_info->unix_info->unix_name,
1752 session_info->info->domain_name);
1754 return NT_STATUS_OK;
1757 NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
1758 uint32_t data_length)
1760 uint16_t needed_charge;
1761 uint16_t credit_charge = 1;
1762 const uint8_t *inhdr;
1764 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1766 if (req->sconn->smb2.supports_multicredit) {
1767 credit_charge = SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE);
1768 credit_charge = MAX(credit_charge, 1);
1771 needed_charge = (data_length - 1)/ 65536 + 1;
1773 DEBUG(10, ("mid %llu, CreditCharge: %d, NeededCharge: %d\n",
1774 (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
1775 credit_charge, needed_charge));
1777 if (needed_charge > credit_charge) {
1778 DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
1779 credit_charge, needed_charge));
1780 return NT_STATUS_INVALID_PARAMETER;
1783 return NT_STATUS_OK;
1786 NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
1787 size_t expected_body_size)
1789 struct iovec *inhdr_v;
1790 const uint8_t *inhdr;
1791 uint16_t opcode;
1792 const uint8_t *inbody;
1793 size_t body_size;
1794 size_t min_dyn_size = expected_body_size & 0x00000001;
1795 int max_idx = req->in.vector_count - SMBD_SMB2_NUM_IOV_PER_REQ;
1798 * The following should be checked already.
1800 if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
1801 return NT_STATUS_INTERNAL_ERROR;
1803 if (req->current_idx > max_idx) {
1804 return NT_STATUS_INTERNAL_ERROR;
1807 inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
1808 if (inhdr_v->iov_len != SMB2_HDR_BODY) {
1809 return NT_STATUS_INTERNAL_ERROR;
1811 if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
1812 return NT_STATUS_INTERNAL_ERROR;
1815 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1816 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1818 switch (opcode) {
1819 case SMB2_OP_IOCTL:
1820 case SMB2_OP_GETINFO:
1821 min_dyn_size = 0;
1822 break;
1826 * Now check the expected body size,
1827 * where the last byte might be in the
1828 * dynamic section..
1830 if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
1831 return NT_STATUS_INVALID_PARAMETER;
1833 if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
1834 return NT_STATUS_INVALID_PARAMETER;
1837 inbody = SMBD_SMB2_IN_BODY_PTR(req);
1839 body_size = SVAL(inbody, 0x00);
1840 if (body_size != expected_body_size) {
1841 return NT_STATUS_INVALID_PARAMETER;
1844 return NT_STATUS_OK;
1847 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
1849 struct smbXsrv_connection *conn = req->sconn->conn;
1850 const struct smbd_smb2_dispatch_table *call = NULL;
1851 const struct iovec *intf_v = SMBD_SMB2_IN_TF_IOV(req);
1852 const uint8_t *inhdr;
1853 uint16_t opcode;
1854 uint32_t flags;
1855 uint64_t mid;
1856 NTSTATUS status;
1857 NTSTATUS session_status;
1858 uint32_t allowed_flags;
1859 NTSTATUS return_value;
1860 struct smbXsrv_session *x = NULL;
1861 bool signing_required = false;
1862 bool encryption_required = false;
1864 inhdr = SMBD_SMB2_IN_HDR_PTR(req);
1866 /* TODO: verify more things */
1868 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
1869 opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
1870 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
1871 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
1872 smb2_opcode_name(opcode),
1873 (unsigned long long)mid));
1875 if (conn->protocol >= PROTOCOL_SMB2_02) {
1877 * once the protocol is negotiated
1878 * SMB2_OP_NEGPROT is not allowed anymore
1880 if (opcode == SMB2_OP_NEGPROT) {
1881 /* drop the connection */
1882 return NT_STATUS_INVALID_PARAMETER;
1884 } else {
1886 * if the protocol is not negotiated yet
1887 * only SMB2_OP_NEGPROT is allowed.
1889 if (opcode != SMB2_OP_NEGPROT) {
1890 /* drop the connection */
1891 return NT_STATUS_INVALID_PARAMETER;
1896 * Check if the client provided a valid session id,
1897 * if so smbd_smb2_request_check_session() calls
1898 * set_current_user_info().
1900 * As some command don't require a valid session id
1901 * we defer the check of the session_status
1903 session_status = smbd_smb2_request_check_session(req);
1904 x = req->session;
1905 if (x != NULL) {
1906 signing_required = x->global->signing_required;
1907 encryption_required = x->global->encryption_required;
1909 if (opcode == SMB2_OP_SESSSETUP &&
1910 x->global->channels[0].signing_key.length) {
1911 signing_required = true;
1915 req->do_signing = false;
1916 req->do_encryption = false;
1917 if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
1918 const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
1919 uint64_t tf_session_id = BVAL(intf, SMB2_TF_SESSION_ID);
1921 if (x != NULL && x->global->session_wire_id != tf_session_id) {
1922 DEBUG(0,("smbd_smb2_request_dispatch: invalid session_id"
1923 "in SMB2_HDR[%llu], SMB2_TF[%llu]\n",
1924 (unsigned long long)x->global->session_wire_id,
1925 (unsigned long long)tf_session_id));
1927 * TODO: windows allows this...
1928 * should we drop the connection?
1930 * For now we just return ACCESS_DENIED
1931 * (Windows clients never trigger this)
1932 * and wait for an update of [MS-SMB2].
1934 return smbd_smb2_request_error(req,
1935 NT_STATUS_ACCESS_DENIED);
1938 req->do_encryption = true;
1941 if (encryption_required && !req->do_encryption) {
1942 return smbd_smb2_request_error(req,
1943 NT_STATUS_ACCESS_DENIED);
1946 call = smbd_smb2_call(opcode);
1947 if (call == NULL) {
1948 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1951 allowed_flags = SMB2_HDR_FLAG_CHAINED |
1952 SMB2_HDR_FLAG_SIGNED |
1953 SMB2_HDR_FLAG_DFS;
1954 if (opcode == SMB2_OP_CANCEL) {
1955 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
1957 if ((flags & ~allowed_flags) != 0) {
1958 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1961 if (flags & SMB2_HDR_FLAG_CHAINED) {
1963 * This check is mostly for giving the correct error code
1964 * for compounded requests.
1966 if (!NT_STATUS_IS_OK(session_status)) {
1967 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1969 } else {
1970 req->compat_chain_fsp = NULL;
1973 if (req->do_encryption) {
1974 signing_required = false;
1975 } else if (flags & SMB2_HDR_FLAG_SIGNED) {
1976 DATA_BLOB signing_key;
1978 if (x == NULL) {
1979 return smbd_smb2_request_error(
1980 req, NT_STATUS_ACCESS_DENIED);
1983 signing_key = x->global->channels[0].signing_key;
1986 * If we have a signing key, we should
1987 * sign the response
1989 if (signing_key.length > 0) {
1990 req->do_signing = true;
1993 status = smb2_signing_check_pdu(signing_key,
1994 conn->protocol,
1995 SMBD_SMB2_IN_HDR_IOV(req),
1996 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
1997 if (!NT_STATUS_IS_OK(status)) {
1998 return smbd_smb2_request_error(req, status);
2002 * Now that we know the request was correctly signed
2003 * we have to sign the response too.
2005 req->do_signing = true;
2007 if (!NT_STATUS_IS_OK(session_status)) {
2008 return smbd_smb2_request_error(req, session_status);
2010 } else if (opcode == SMB2_OP_CANCEL) {
2011 /* Cancel requests are allowed to skip the signing */
2012 } else if (signing_required) {
2014 * If signing is required we try to sign
2015 * a possible error response
2017 req->do_signing = true;
2018 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
2021 if (flags & SMB2_HDR_FLAG_CHAINED) {
2022 req->compound_related = true;
2025 if (call->need_session) {
2026 if (!NT_STATUS_IS_OK(session_status)) {
2027 return smbd_smb2_request_error(req, session_status);
2031 if (call->need_tcon) {
2032 SMB_ASSERT(call->need_session);
2035 * This call needs to be run as user.
2037 * smbd_smb2_request_check_tcon()
2038 * calls change_to_user() on success.
2040 status = smbd_smb2_request_check_tcon(req);
2041 if (!NT_STATUS_IS_OK(status)) {
2042 return smbd_smb2_request_error(req, status);
2044 if (req->tcon->global->encryption_required) {
2045 encryption_required = true;
2047 if (encryption_required && !req->do_encryption) {
2048 return smbd_smb2_request_error(req,
2049 NT_STATUS_ACCESS_DENIED);
2053 if (call->fileid_ofs != 0) {
2054 size_t needed = call->fileid_ofs + 16;
2055 const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
2056 size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
2057 uint64_t file_id_persistent;
2058 uint64_t file_id_volatile;
2059 struct files_struct *fsp;
2061 SMB_ASSERT(call->need_tcon);
2063 if (needed > body_size) {
2064 return smbd_smb2_request_error(req,
2065 NT_STATUS_INVALID_PARAMETER);
2068 file_id_persistent = BVAL(body, call->fileid_ofs + 0);
2069 file_id_volatile = BVAL(body, call->fileid_ofs + 8);
2071 fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
2072 if (fsp == NULL) {
2073 if (!call->allow_invalid_fileid) {
2074 return smbd_smb2_request_error(req,
2075 NT_STATUS_FILE_CLOSED);
2078 if (file_id_persistent != UINT64_MAX) {
2079 return smbd_smb2_request_error(req,
2080 NT_STATUS_FILE_CLOSED);
2082 if (file_id_volatile != UINT64_MAX) {
2083 return smbd_smb2_request_error(req,
2084 NT_STATUS_FILE_CLOSED);
2089 if (call->as_root) {
2090 SMB_ASSERT(call->fileid_ofs == 0);
2091 /* This call needs to be run as root */
2092 change_to_root_user();
2093 } else {
2094 SMB_ASSERT(call->need_tcon);
2097 switch (opcode) {
2098 case SMB2_OP_NEGPROT:
2100 START_PROFILE(smb2_negprot);
2101 return_value = smbd_smb2_request_process_negprot(req);
2102 END_PROFILE(smb2_negprot);
2104 break;
2106 case SMB2_OP_SESSSETUP:
2108 START_PROFILE(smb2_sesssetup);
2109 return_value = smbd_smb2_request_process_sesssetup(req);
2110 END_PROFILE(smb2_sesssetup);
2112 break;
2114 case SMB2_OP_LOGOFF:
2116 START_PROFILE(smb2_logoff);
2117 return_value = smbd_smb2_request_process_logoff(req);
2118 END_PROFILE(smb2_logoff);
2120 break;
2122 case SMB2_OP_TCON:
2124 START_PROFILE(smb2_tcon);
2125 return_value = smbd_smb2_request_process_tcon(req);
2126 END_PROFILE(smb2_tcon);
2128 break;
2130 case SMB2_OP_TDIS:
2132 START_PROFILE(smb2_tdis);
2133 return_value = smbd_smb2_request_process_tdis(req);
2134 END_PROFILE(smb2_tdis);
2136 break;
2138 case SMB2_OP_CREATE:
2140 START_PROFILE(smb2_create);
2141 return_value = smbd_smb2_request_process_create(req);
2142 END_PROFILE(smb2_create);
2144 break;
2146 case SMB2_OP_CLOSE:
2148 START_PROFILE(smb2_close);
2149 return_value = smbd_smb2_request_process_close(req);
2150 END_PROFILE(smb2_close);
2152 break;
2154 case SMB2_OP_FLUSH:
2156 START_PROFILE(smb2_flush);
2157 return_value = smbd_smb2_request_process_flush(req);
2158 END_PROFILE(smb2_flush);
2160 break;
2162 case SMB2_OP_READ:
2164 START_PROFILE(smb2_read);
2165 return_value = smbd_smb2_request_process_read(req);
2166 END_PROFILE(smb2_read);
2168 break;
2170 case SMB2_OP_WRITE:
2172 START_PROFILE(smb2_write);
2173 return_value = smbd_smb2_request_process_write(req);
2174 END_PROFILE(smb2_write);
2176 break;
2178 case SMB2_OP_LOCK:
2180 START_PROFILE(smb2_lock);
2181 return_value = smbd_smb2_request_process_lock(req);
2182 END_PROFILE(smb2_lock);
2184 break;
2186 case SMB2_OP_IOCTL:
2188 START_PROFILE(smb2_ioctl);
2189 return_value = smbd_smb2_request_process_ioctl(req);
2190 END_PROFILE(smb2_ioctl);
2192 break;
2194 case SMB2_OP_CANCEL:
2196 START_PROFILE(smb2_cancel);
2197 return_value = smbd_smb2_request_process_cancel(req);
2198 END_PROFILE(smb2_cancel);
2200 break;
2202 case SMB2_OP_KEEPALIVE:
2204 START_PROFILE(smb2_keepalive);
2205 return_value = smbd_smb2_request_process_keepalive(req);
2206 END_PROFILE(smb2_keepalive);
2208 break;
2210 case SMB2_OP_FIND:
2212 START_PROFILE(smb2_find);
2213 return_value = smbd_smb2_request_process_find(req);
2214 END_PROFILE(smb2_find);
2216 break;
2218 case SMB2_OP_NOTIFY:
2220 START_PROFILE(smb2_notify);
2221 return_value = smbd_smb2_request_process_notify(req);
2222 END_PROFILE(smb2_notify);
2224 break;
2226 case SMB2_OP_GETINFO:
2228 START_PROFILE(smb2_getinfo);
2229 return_value = smbd_smb2_request_process_getinfo(req);
2230 END_PROFILE(smb2_getinfo);
2232 break;
2234 case SMB2_OP_SETINFO:
2236 START_PROFILE(smb2_setinfo);
2237 return_value = smbd_smb2_request_process_setinfo(req);
2238 END_PROFILE(smb2_setinfo);
2240 break;
2242 case SMB2_OP_BREAK:
2244 START_PROFILE(smb2_break);
2245 return_value = smbd_smb2_request_process_break(req);
2246 END_PROFILE(smb2_break);
2248 break;
2250 default:
2251 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
2252 break;
2254 return return_value;
2257 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
2259 struct smbd_server_connection *sconn = req->sconn;
2260 struct smbXsrv_connection *conn = req->sconn->conn;
2261 int first_idx = 1;
2262 struct iovec *firsttf = SMBD_SMB2_IDX_TF_IOV(req,out,first_idx);
2263 struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req);
2264 struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req);
2265 NTSTATUS status;
2267 req->subreq = NULL;
2268 TALLOC_FREE(req->async_te);
2270 if (req->do_encryption &&
2271 (firsttf->iov_len == 0) &&
2272 (req->first_key.length == 0) &&
2273 (req->session != NULL) &&
2274 (req->session->global->encryption_key.length != 0))
2276 DATA_BLOB encryption_key = req->session->global->encryption_key;
2277 uint8_t *tf;
2278 uint64_t session_id = req->session->global->session_wire_id;
2279 struct smbXsrv_session *x = req->session;
2280 uint64_t nonce_high;
2281 uint64_t nonce_low;
2283 nonce_high = x->nonce_high;
2284 nonce_low = x->nonce_low;
2286 x->nonce_low += 1;
2287 if (x->nonce_low == 0) {
2288 x->nonce_low += 1;
2289 x->nonce_high += 1;
2293 * We need to place the SMB2_TRANSFORM header before the
2294 * first SMB2 header
2298 * we need to remember the encryption key
2299 * and defer the signing/encryption until
2300 * we are sure that we do not change
2301 * the header again.
2303 req->first_key = data_blob_dup_talloc(req, encryption_key);
2304 if (req->first_key.data == NULL) {
2305 return NT_STATUS_NO_MEMORY;
2308 tf = talloc_zero_array(req->out.vector, uint8_t,
2309 SMB2_TF_HDR_SIZE);
2310 if (tf == NULL) {
2311 return NT_STATUS_NO_MEMORY;
2314 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2315 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2316 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2317 SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
2319 firsttf->iov_base = (void *)tf;
2320 firsttf->iov_len = SMB2_TF_HDR_SIZE;
2323 if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) &&
2324 (req->last_key.length > 0) &&
2325 (firsttf->iov_len == 0))
2327 int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
2328 struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
2331 * As we are sure the header of the last request in the
2332 * compound chain will not change, we can to sign here
2333 * with the last signing key we remembered.
2335 status = smb2_signing_sign_pdu(req->last_key,
2336 conn->protocol,
2337 lasthdr,
2338 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2339 if (!NT_STATUS_IS_OK(status)) {
2340 return status;
2343 data_blob_clear_free(&req->last_key);
2345 req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ;
2347 if (req->current_idx < req->out.vector_count) {
2349 * We must process the remaining compound
2350 * SMB2 requests before any new incoming SMB2
2351 * requests. This is because incoming SMB2
2352 * requests may include a cancel for a
2353 * compound request we haven't processed
2354 * yet.
2356 struct tevent_immediate *im = tevent_create_immediate(req);
2357 if (!im) {
2358 return NT_STATUS_NO_MEMORY;
2361 if (req->do_signing && firsttf->iov_len == 0) {
2362 struct smbXsrv_session *x = req->session;
2363 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2366 * we need to remember the signing key
2367 * and defer the signing until
2368 * we are sure that we do not change
2369 * the header again.
2371 req->last_key = data_blob_dup_talloc(req, signing_key);
2372 if (req->last_key.data == NULL) {
2373 return NT_STATUS_NO_MEMORY;
2377 tevent_schedule_immediate(im,
2378 req->sconn->ev_ctx,
2379 smbd_smb2_request_dispatch_immediate,
2380 req);
2381 return NT_STATUS_OK;
2384 if (req->compound_related) {
2385 req->compound_related = false;
2388 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
2390 /* Set credit for these operations (zero credits if this
2391 is a final reply for an async operation). */
2392 smb2_calculate_credits(req, req);
2395 * now check if we need to sign the current response
2397 if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
2398 status = smb2_signing_encrypt_pdu(req->first_key,
2399 conn->protocol,
2400 firsttf,
2401 req->out.vector_count - first_idx);
2402 if (!NT_STATUS_IS_OK(status)) {
2403 return status;
2405 } else if (req->do_signing) {
2406 struct smbXsrv_session *x = req->session;
2407 DATA_BLOB signing_key = x->global->channels[0].signing_key;
2409 status = smb2_signing_sign_pdu(signing_key,
2410 conn->protocol,
2411 outhdr,
2412 SMBD_SMB2_NUM_IOV_PER_REQ - 1);
2413 if (!NT_STATUS_IS_OK(status)) {
2414 return status;
2417 data_blob_clear_free(&req->first_key);
2419 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
2420 if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) &&
2421 outdyn->iov_base == NULL && outdyn->iov_len != 0) {
2422 /* Dynamic part is NULL. Chop it off,
2423 We're going to send it via sendfile. */
2424 req->out.vector_count -= 1;
2428 * We're done with this request -
2429 * move it off the "being processed" queue.
2431 DLIST_REMOVE(req->sconn->smb2.requests, req);
2433 req->queue_entry.mem_ctx = req;
2434 req->queue_entry.vector = req->out.vector;
2435 req->queue_entry.count = req->out.vector_count;
2436 DLIST_ADD_END(req->sconn->smb2.send_queue, &req->queue_entry, NULL);
2437 req->sconn->smb2.send_queue_len++;
2439 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2440 if (!NT_STATUS_IS_OK(status)) {
2441 return status;
2444 return NT_STATUS_OK;
2447 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
2449 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
2450 struct tevent_immediate *im,
2451 void *private_data)
2453 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
2454 struct smbd_smb2_request);
2455 struct smbd_server_connection *sconn = req->sconn;
2456 NTSTATUS status;
2458 TALLOC_FREE(im);
2460 if (DEBUGLEVEL >= 10) {
2461 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
2462 req->current_idx, req->in.vector_count));
2463 print_req_vectors(req);
2466 status = smbd_smb2_request_dispatch(req);
2467 if (!NT_STATUS_IS_OK(status)) {
2468 smbd_server_connection_terminate(sconn, nt_errstr(status));
2469 return;
2472 status = smbd_smb2_request_next_incoming(sconn);
2473 if (!NT_STATUS_IS_OK(status)) {
2474 smbd_server_connection_terminate(sconn, nt_errstr(status));
2475 return;
2479 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
2480 NTSTATUS status,
2481 DATA_BLOB body, DATA_BLOB *dyn,
2482 const char *location)
2484 uint8_t *outhdr;
2485 struct iovec *outbody_v;
2486 struct iovec *outdyn_v;
2487 uint32_t next_command_ofs;
2489 DEBUG(10,("smbd_smb2_request_done_ex: "
2490 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
2491 req->current_idx, nt_errstr(status), (unsigned int)body.length,
2492 dyn ? "yes": "no",
2493 (unsigned int)(dyn ? dyn->length : 0),
2494 location));
2496 if (body.length < 2) {
2497 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2500 if ((body.length % 2) != 0) {
2501 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
2504 outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2505 outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
2506 outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
2508 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
2509 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
2511 outbody_v->iov_base = (void *)body.data;
2512 outbody_v->iov_len = body.length;
2514 if (dyn) {
2515 outdyn_v->iov_base = (void *)dyn->data;
2516 outdyn_v->iov_len = dyn->length;
2517 } else {
2518 outdyn_v->iov_base = NULL;
2519 outdyn_v->iov_len = 0;
2522 /* see if we need to recalculate the offset to the next response */
2523 if (next_command_ofs > 0) {
2524 next_command_ofs = SMB2_HDR_BODY;
2525 next_command_ofs += SMBD_SMB2_OUT_BODY_LEN(req);
2526 next_command_ofs += SMBD_SMB2_OUT_DYN_LEN(req);
2529 if ((next_command_ofs % 8) != 0) {
2530 size_t pad_size = 8 - (next_command_ofs % 8);
2531 if (SMBD_SMB2_OUT_DYN_LEN(req) == 0) {
2533 * if the dyn buffer is empty
2534 * we can use it to add padding
2536 uint8_t *pad;
2538 pad = talloc_zero_array(req->out.vector,
2539 uint8_t, pad_size);
2540 if (pad == NULL) {
2541 return smbd_smb2_request_error(req,
2542 NT_STATUS_NO_MEMORY);
2545 outdyn_v->iov_base = (void *)pad;
2546 outdyn_v->iov_len = pad_size;
2547 } else {
2549 * For now we copy the dynamic buffer
2550 * and add the padding to the new buffer
2552 size_t old_size;
2553 uint8_t *old_dyn;
2554 size_t new_size;
2555 uint8_t *new_dyn;
2557 old_size = SMBD_SMB2_OUT_DYN_LEN(req);
2558 old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
2560 new_size = old_size + pad_size;
2561 new_dyn = talloc_zero_array(req->out.vector,
2562 uint8_t, new_size);
2563 if (new_dyn == NULL) {
2564 return smbd_smb2_request_error(req,
2565 NT_STATUS_NO_MEMORY);
2568 memcpy(new_dyn, old_dyn, old_size);
2569 memset(new_dyn + old_size, 0, pad_size);
2571 outdyn_v->iov_base = (void *)new_dyn;
2572 outdyn_v->iov_len = new_size;
2574 next_command_ofs += pad_size;
2577 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
2579 return smbd_smb2_request_reply(req);
2582 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
2583 NTSTATUS status,
2584 DATA_BLOB *info,
2585 const char *location)
2587 DATA_BLOB body;
2588 uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
2589 size_t unread_bytes = smbd_smb2_unread_bytes(req);
2591 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
2592 req->current_idx, nt_errstr(status), info ? " +info" : "",
2593 location));
2595 if (unread_bytes) {
2596 /* Recvfile error. Drain incoming socket. */
2597 size_t ret;
2599 errno = 0;
2600 ret = drain_socket(req->sconn->sock, unread_bytes);
2601 if (ret != unread_bytes) {
2602 NTSTATUS error;
2604 if (errno == 0) {
2605 error = NT_STATUS_IO_DEVICE_ERROR;
2606 } else {
2607 error = map_nt_error_from_unix_common(errno);
2610 DEBUG(2, ("Failed to drain %u bytes from SMB2 socket: "
2611 "ret[%u] errno[%d] => %s\n",
2612 (unsigned)unread_bytes,
2613 (unsigned)ret, errno, nt_errstr(error)));
2614 return error;
2618 body.data = outhdr + SMB2_HDR_BODY;
2619 body.length = 8;
2620 SSVAL(body.data, 0, 9);
2622 if (info) {
2623 SIVAL(body.data, 0x04, info->length);
2624 } else {
2625 /* Allocated size of req->out.vector[i].iov_base
2626 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
2627 * 1 byte without having to do an alloc.
2629 info = talloc_zero_array(req->out.vector,
2630 DATA_BLOB,
2632 if (!info) {
2633 return NT_STATUS_NO_MEMORY;
2635 info->data = ((uint8_t *)outhdr) +
2636 OUTVEC_ALLOC_SIZE - 1;
2637 info->length = 1;
2638 SCVAL(info->data, 0, 0);
2642 * Note: Even if there is an error, continue to process the request.
2643 * per MS-SMB2.
2646 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
2650 struct smbd_smb2_send_oplock_break_state {
2651 struct smbd_server_connection *sconn;
2652 struct smbd_smb2_send_queue queue_entry;
2653 uint8_t buf[NBT_HDR_SIZE + SMB2_TF_HDR_SIZE + SMB2_HDR_BODY + 0x18];
2654 struct iovec vector[1+SMBD_SMB2_NUM_IOV_PER_REQ];
2657 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
2658 struct smbXsrv_session *session,
2659 struct smbXsrv_tcon *tcon,
2660 struct smbXsrv_open *op,
2661 uint8_t oplock_level)
2663 struct smbd_smb2_send_oplock_break_state *state;
2664 struct smbXsrv_connection *conn = sconn->conn;
2665 uint8_t *tf;
2666 size_t tf_len;
2667 uint8_t *hdr;
2668 uint8_t *body;
2669 size_t body_len;
2670 uint8_t *dyn;
2671 size_t dyn_len;
2672 bool do_encryption = session->global->encryption_required;
2673 uint64_t nonce_high = 0;
2674 uint64_t nonce_low = 0;
2675 NTSTATUS status;
2677 if (tcon->global->encryption_required) {
2678 do_encryption = true;
2681 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
2682 if (state == NULL) {
2683 return NT_STATUS_NO_MEMORY;
2685 state->sconn = sconn;
2687 tf = state->buf + NBT_HDR_SIZE;
2688 tf_len = SMB2_TF_HDR_SIZE;
2689 hdr = tf + tf_len;
2690 body = hdr + SMB2_HDR_BODY;
2691 body_len = 0x18;
2692 dyn = body + body_len;
2693 dyn_len = 0;
2695 if (do_encryption) {
2696 nonce_high = session->nonce_high;
2697 nonce_low = session->nonce_low;
2699 session->nonce_low += 1;
2700 if (session->nonce_low == 0) {
2701 session->nonce_low += 1;
2702 session->nonce_high += 1;
2706 SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
2707 SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
2708 SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
2709 SBVAL(tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
2711 SIVAL(hdr, 0, SMB2_MAGIC);
2712 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
2713 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
2714 SIVAL(hdr, SMB2_HDR_STATUS, 0);
2715 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
2716 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
2717 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
2718 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
2719 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
2720 SIVAL(hdr, SMB2_HDR_PID, 0);
2721 SIVAL(hdr, SMB2_HDR_TID, 0);
2722 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
2723 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
2725 SSVAL(body, 0x00, body_len);
2727 SCVAL(body, 0x02, oplock_level);
2728 SCVAL(body, 0x03, 0); /* reserved */
2729 SIVAL(body, 0x04, 0); /* reserved */
2730 SBVAL(body, 0x08, op->global->open_persistent_id);
2731 SBVAL(body, 0x10, op->global->open_volatile_id);
2733 state->vector[0].iov_base = (void *)state->buf;
2734 state->vector[0].iov_len = NBT_HDR_SIZE;
2736 if (do_encryption) {
2737 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
2738 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
2739 } else {
2740 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
2741 state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
2744 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr;
2745 state->vector[1+SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY;
2747 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_base = body;
2748 state->vector[1+SMBD_SMB2_BODY_IOV_OFS].iov_len = body_len;
2750 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn;
2751 state->vector[1+SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_len;
2753 smb2_setup_nbt_length(state->vector, 1 + SMBD_SMB2_NUM_IOV_PER_REQ);
2755 if (do_encryption) {
2756 DATA_BLOB encryption_key = session->global->encryption_key;
2758 status = smb2_signing_encrypt_pdu(encryption_key,
2759 conn->protocol,
2760 &state->vector[1+SMBD_SMB2_TF_IOV_OFS],
2761 SMBD_SMB2_NUM_IOV_PER_REQ);
2762 if (!NT_STATUS_IS_OK(status)) {
2763 return status;
2767 state->queue_entry.mem_ctx = state;
2768 state->queue_entry.vector = state->vector;
2769 state->queue_entry.count = ARRAY_SIZE(state->vector);
2770 DLIST_ADD_END(state->sconn->smb2.send_queue, &state->queue_entry, NULL);
2771 state->sconn->smb2.send_queue_len++;
2773 status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
2774 if (!NT_STATUS_IS_OK(status)) {
2775 return status;
2778 return NT_STATUS_OK;
2781 static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
2783 if (smb2_req->do_signing) {
2784 return 0;
2786 if (smb2_req->do_encryption) {
2787 return 0;
2789 return (size_t)lp_min_receive_file_size();
2792 static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
2794 uint32_t flags;
2796 if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
2797 /* Transform header. Cannot recvfile. */
2798 return false;
2800 if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
2801 /* Not SMB2. Normal error path will cope. */
2802 return false;
2804 if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
2805 /* Not SMB2. Normal error path will cope. */
2806 return false;
2808 if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
2809 /* Needs to be a WRITE. */
2810 return false;
2812 if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
2813 /* Chained. Cannot recvfile. */
2814 return false;
2816 flags = IVAL(state->pktbuf, SMB2_HDR_FLAGS);
2817 if (flags & SMB2_HDR_FLAG_CHAINED) {
2818 /* Chained. Cannot recvfile. */
2819 return false;
2821 if (flags & SMB2_HDR_FLAG_SIGNED) {
2822 /* Signed. Cannot recvfile. */
2823 return false;
2826 DEBUG(10,("Doing recvfile write len = %u\n",
2827 (unsigned int)(state->pktlen -
2828 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
2830 return true;
2833 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
2835 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
2836 size_t max_send_queue_len;
2837 size_t cur_send_queue_len;
2839 if (state->req != NULL) {
2841 * if there is already a tstream_readv_pdu
2842 * pending, we are done.
2844 return NT_STATUS_OK;
2847 max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
2848 cur_send_queue_len = sconn->smb2.send_queue_len;
2850 if (cur_send_queue_len > max_send_queue_len) {
2852 * if we have a lot of requests to send,
2853 * we wait until they are on the wire until we
2854 * ask for the next request.
2856 return NT_STATUS_OK;
2859 /* ask for the next request */
2860 ZERO_STRUCTP(state);
2861 state->req = smbd_smb2_request_allocate(sconn);
2862 if (state->req == NULL) {
2863 return NT_STATUS_NO_MEMORY;
2865 state->req->sconn = sconn;
2866 state->min_recv_size = get_min_receive_file_size(state->req);
2868 TEVENT_FD_READABLE(sconn->smb2.fde);
2870 return NT_STATUS_OK;
2873 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
2874 uint8_t *inbuf, size_t size)
2876 NTSTATUS status;
2877 struct smbd_smb2_request *req = NULL;
2879 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
2880 (unsigned int)size));
2882 status = smbd_initialize_smb2(sconn);
2883 if (!NT_STATUS_IS_OK(status)) {
2884 smbd_server_connection_terminate(sconn, nt_errstr(status));
2885 return;
2888 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
2889 if (!NT_STATUS_IS_OK(status)) {
2890 smbd_server_connection_terminate(sconn, nt_errstr(status));
2891 return;
2894 status = smbd_smb2_request_validate(req);
2895 if (!NT_STATUS_IS_OK(status)) {
2896 smbd_server_connection_terminate(sconn, nt_errstr(status));
2897 return;
2900 status = smbd_smb2_request_setup_out(req);
2901 if (!NT_STATUS_IS_OK(status)) {
2902 smbd_server_connection_terminate(sconn, nt_errstr(status));
2903 return;
2906 status = smbd_smb2_request_dispatch(req);
2907 if (!NT_STATUS_IS_OK(status)) {
2908 smbd_server_connection_terminate(sconn, nt_errstr(status));
2909 return;
2912 status = smbd_smb2_request_next_incoming(sconn);
2913 if (!NT_STATUS_IS_OK(status)) {
2914 smbd_server_connection_terminate(sconn, nt_errstr(status));
2915 return;
2918 sconn->num_requests++;
2921 static int socket_error_from_errno(int ret,
2922 int sys_errno,
2923 bool *retry)
2925 *retry = false;
2927 if (ret >= 0) {
2928 return 0;
2931 if (ret != -1) {
2932 return EIO;
2935 if (sys_errno == 0) {
2936 return EIO;
2939 if (sys_errno == EINTR) {
2940 *retry = true;
2941 return sys_errno;
2944 if (sys_errno == EINPROGRESS) {
2945 *retry = true;
2946 return sys_errno;
2949 if (sys_errno == EAGAIN) {
2950 *retry = true;
2951 return sys_errno;
2954 /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
2955 if (sys_errno == ENOMEM) {
2956 *retry = true;
2957 return sys_errno;
2960 #ifdef EWOULDBLOCK
2961 if (sys_errno == EWOULDBLOCK) {
2962 *retry = true;
2963 return sys_errno;
2965 #endif
2967 return sys_errno;
2970 static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn)
2972 int ret;
2973 int err;
2974 bool retry;
2976 if (sconn->smb2.send_queue == NULL) {
2977 TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
2978 return NT_STATUS_OK;
2981 while (sconn->smb2.send_queue != NULL) {
2982 struct smbd_smb2_send_queue *e = sconn->smb2.send_queue;
2984 ret = writev(sconn->sock, e->vector, e->count);
2985 if (ret == 0) {
2986 /* propagate end of file */
2987 return NT_STATUS_INTERNAL_ERROR;
2989 err = socket_error_from_errno(ret, errno, &retry);
2990 if (retry) {
2991 /* retry later */
2992 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
2993 return NT_STATUS_OK;
2995 if (err != 0) {
2996 return map_nt_error_from_unix_common(err);
2998 while (ret > 0) {
2999 if (ret < e->vector[0].iov_len) {
3000 uint8_t *base;
3001 base = (uint8_t *)e->vector[0].iov_base;
3002 base += ret;
3003 e->vector[0].iov_base = (void *)base;
3004 e->vector[0].iov_len -= ret;
3005 break;
3007 ret -= e->vector[0].iov_len;
3008 e->vector += 1;
3009 e->count -= 1;
3013 * there're maybe some empty vectors at the end
3014 * which we need to skip, otherwise we would get
3015 * ret == 0 from the readv() call and return EPIPE
3017 while (e->count > 0) {
3018 if (e->vector[0].iov_len > 0) {
3019 break;
3021 e->vector += 1;
3022 e->count -= 1;
3025 if (e->count > 0) {
3026 /* we have more to write */
3027 TEVENT_FD_WRITEABLE(sconn->smb2.fde);
3028 return NT_STATUS_OK;
3031 sconn->smb2.send_queue_len--;
3032 DLIST_REMOVE(sconn->smb2.send_queue, e);
3033 talloc_free(e->mem_ctx);
3036 return NT_STATUS_OK;
3039 static NTSTATUS smbd_smb2_io_handler(struct smbd_server_connection *sconn,
3040 uint16_t fde_flags)
3042 struct smbd_smb2_request_read_state *state = &sconn->smb2.request_read_state;
3043 struct smbd_smb2_request *req = NULL;
3044 size_t min_recvfile_size = UINT32_MAX;
3045 int ret;
3046 int err;
3047 bool retry;
3048 NTSTATUS status;
3049 NTTIME now;
3051 if (fde_flags & TEVENT_FD_WRITE) {
3052 status = smbd_smb2_flush_send_queue(sconn);
3053 if (!NT_STATUS_IS_OK(status)) {
3054 return status;
3058 if (!(fde_flags & TEVENT_FD_READ)) {
3059 return NT_STATUS_OK;
3062 if (state->req == NULL) {
3063 TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
3064 return NT_STATUS_OK;
3067 again:
3068 if (!state->hdr.done) {
3069 state->hdr.done = true;
3071 state->vector.iov_base = (void *)state->hdr.nbt;
3072 state->vector.iov_len = NBT_HDR_SIZE;
3075 ret = readv(sconn->sock, &state->vector, 1);
3076 if (ret == 0) {
3077 /* propagate end of file */
3078 return NT_STATUS_END_OF_FILE;
3080 err = socket_error_from_errno(ret, errno, &retry);
3081 if (retry) {
3082 /* retry later */
3083 TEVENT_FD_READABLE(sconn->smb2.fde);
3084 return NT_STATUS_OK;
3086 if (err != 0) {
3087 return map_nt_error_from_unix_common(err);
3090 if (ret < state->vector.iov_len) {
3091 uint8_t *base;
3092 base = (uint8_t *)state->vector.iov_base;
3093 base += ret;
3094 state->vector.iov_base = (void *)base;
3095 state->vector.iov_len -= ret;
3096 /* we have more to read */
3097 TEVENT_FD_READABLE(sconn->smb2.fde);
3098 return NT_STATUS_OK;
3101 if (state->pktlen > 0) {
3102 if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
3104 * Not a possible receivefile write.
3105 * Read the rest of the data.
3107 state->doing_receivefile = false;
3108 state->vector.iov_base = (void *)(state->pktbuf +
3109 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3110 state->vector.iov_len = (state->pktlen -
3111 SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
3112 goto again;
3116 * Either this is a receivefile write so we've
3117 * done a short read, or if not we have all the data.
3119 goto got_full;
3123 * Now we analyze the NBT header
3125 state->pktlen = smb2_len(state->hdr.nbt);
3126 if (state->pktlen == 0) {
3127 goto got_full;
3130 state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
3131 if (state->pktbuf == NULL) {
3132 return NT_STATUS_NO_MEMORY;
3135 state->vector.iov_base = (void *)state->pktbuf;
3137 if (state->min_recv_size != 0) {
3138 min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3139 min_recvfile_size += state->min_recv_size;
3142 if (state->pktlen > min_recvfile_size) {
3144 * Might be a receivefile write. Read the SMB2 HEADER +
3145 * SMB2_WRITE header first. Set 'doing_receivefile'
3146 * as we're *attempting* receivefile write. If this
3147 * turns out not to be a SMB2_WRITE request or otherwise
3148 * not suitable then we'll just read the rest of the data
3149 * the next time this function is called.
3151 state->vector.iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3152 state->doing_receivefile = true;
3153 } else {
3154 state->vector.iov_len = state->pktlen;
3157 goto again;
3159 got_full:
3161 if (state->hdr.nbt[0] != 0x00) {
3162 DEBUG(1,("ignore NBT[0x%02X] msg\n",
3163 state->hdr.nbt[0]));
3165 req = state->req;
3166 ZERO_STRUCTP(state);
3167 state->req = req;
3168 state->min_recv_size = get_min_receive_file_size(state->req);
3169 req = NULL;
3170 goto again;
3173 req = state->req;
3174 state->req = NULL;
3176 req->request_time = timeval_current();
3177 now = timeval_to_nttime(&req->request_time);
3179 status = smbd_smb2_inbuf_parse_compound(req->sconn->conn,
3180 now,
3181 state->pktbuf,
3182 state->pktlen,
3183 req,
3184 &req->in.vector,
3185 &req->in.vector_count);
3186 if (!NT_STATUS_IS_OK(status)) {
3187 return status;
3190 if (state->doing_receivefile) {
3191 req->smb1req = talloc_zero(req, struct smb_request);
3192 if (req->smb1req == NULL) {
3193 return NT_STATUS_NO_MEMORY;
3195 req->smb1req->unread_bytes =
3196 state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
3199 ZERO_STRUCTP(state);
3201 req->current_idx = 1;
3203 DEBUG(10,("smbd_smb2_request idx[%d] of %d vectors\n",
3204 req->current_idx, req->in.vector_count));
3206 status = smbd_smb2_request_validate(req);
3207 if (!NT_STATUS_IS_OK(status)) {
3208 return status;
3211 status = smbd_smb2_request_setup_out(req);
3212 if (!NT_STATUS_IS_OK(status)) {
3213 return status;
3216 status = smbd_smb2_request_dispatch(req);
3217 if (!NT_STATUS_IS_OK(status)) {
3218 return status;
3221 sconn->num_requests++;
3223 /* The timeout_processing function isn't run nearly
3224 often enough to implement 'max log size' without
3225 overrunning the size of the file by many megabytes.
3226 This is especially true if we are running at debug
3227 level 10. Checking every 50 SMB2s is a nice
3228 tradeoff of performance vs log file size overrun. */
3230 if ((sconn->num_requests % 50) == 0 &&
3231 need_to_check_log_size()) {
3232 change_to_root_user();
3233 check_log_size();
3236 status = smbd_smb2_request_next_incoming(sconn);
3237 if (!NT_STATUS_IS_OK(status)) {
3238 return status;
3241 return NT_STATUS_OK;
3244 static void smbd_smb2_connection_handler(struct tevent_context *ev,
3245 struct tevent_fd *fde,
3246 uint16_t flags,
3247 void *private_data)
3249 struct smbd_server_connection *sconn =
3250 talloc_get_type_abort(private_data,
3251 struct smbd_server_connection);
3252 NTSTATUS status;
3254 status = smbd_smb2_io_handler(sconn, flags);
3255 if (!NT_STATUS_IS_OK(status)) {
3256 smbd_server_connection_terminate(sconn, nt_errstr(status));
3257 return;