Ensure we remove SMB2 cancel requests from the active queue
[Samba/ekacnet.git] / source3 / smbd / smb2_server.c
blobdf2557080bc3327569699621cd7ed9659ee9bd43
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/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../lib/tsocket/tsocket.h"
27 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
29 static const char *smb2_names[] = {
30 "SMB2_NEGPROT",
31 "SMB2_SESSSETUP",
32 "SMB2_LOGOFF",
33 "SMB2_TCON",
34 "SMB2_TDIS",
35 "SMB2_CREATE",
36 "SMB2_CLOSE",
37 "SMB2_FLUSH",
38 "SMB2_READ",
39 "SMB2_WRITE",
40 "SMB2_LOCK",
41 "SMB2_IOCTL",
42 "SMB2_CANCEL",
43 "SMB2_KEEPALIVE",
44 "SMB2_FIND",
45 "SMB2_NOTIFY",
46 "SMB2_GETINFO",
47 "SMB2_SETINFO",
48 "SMB2_BREAK"
51 const char *smb2_opcode_name(uint16_t opcode)
53 if (opcode > 0x12) {
54 return "Bad SMB2 opcode";
56 return smb2_names[opcode];
59 static void print_req_vectors(struct smbd_smb2_request *req)
61 int i;
63 for (i = 0; i < req->in.vector_count; i++) {
64 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
65 (unsigned int)i,
66 (unsigned int)req->in.vector[i].iov_len);
68 for (i = 0; i < req->out.vector_count; i++) {
69 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
70 (unsigned int)i,
71 (unsigned int)req->out.vector[i].iov_len);
75 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
77 if (size < (4 + SMB2_HDR_BODY)) {
78 return false;
81 if (IVAL(inbuf, 4) != SMB2_MAGIC) {
82 return false;
85 return true;
88 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
90 NTSTATUS status;
91 int ret;
93 TALLOC_FREE(sconn->smb1.fde);
95 sconn->smb2.event_ctx = smbd_event_context();
97 sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
98 if (sconn->smb2.recv_queue == NULL) {
99 return NT_STATUS_NO_MEMORY;
102 sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
103 if (sconn->smb2.send_queue == NULL) {
104 return NT_STATUS_NO_MEMORY;
107 sconn->smb2.sessions.idtree = idr_init(sconn);
108 if (sconn->smb2.sessions.idtree == NULL) {
109 return NT_STATUS_NO_MEMORY;
111 sconn->smb2.sessions.limit = 0x0000FFFE;
112 sconn->smb2.sessions.list = NULL;
114 ret = tstream_bsd_existing_socket(sconn, smbd_server_fd(),
115 &sconn->smb2.stream);
116 if (ret == -1) {
117 status = map_nt_error_from_unix(errno);
118 return status;
121 /* Ensure child is set to non-blocking mode */
122 set_blocking(smbd_server_fd(),false);
123 return NT_STATUS_OK;
126 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
127 #define _smb2_setlen(_buf,len) do { \
128 uint8_t *buf = (uint8_t *)_buf; \
129 buf[0] = 0; \
130 buf[1] = ((len)&0xFF0000)>>16; \
131 buf[2] = ((len)&0xFF00)>>8; \
132 buf[3] = (len)&0xFF; \
133 } while (0)
135 static void smb2_setup_nbt_length(struct iovec *vector, int count)
137 size_t len = 0;
138 int i;
140 for (i=1; i < count; i++) {
141 len += vector[i].iov_len;
144 _smb2_setlen(vector[0].iov_base, len);
147 static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
149 if (*req) {
150 (*req)->parent = NULL;
151 (*req)->mem_pool = NULL;
154 return 0;
157 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
159 if (req->parent) {
160 *req->parent = NULL;
161 talloc_free(req->mem_pool);
164 return 0;
167 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
169 TALLOC_CTX *mem_pool;
170 struct smbd_smb2_request **parent;
171 struct smbd_smb2_request *req;
173 #if 0
174 /* Enable this to find subtle valgrind errors. */
175 mem_pool = talloc_init("smbd_smb2_request_allocate");
176 #else
177 mem_pool = talloc_pool(mem_ctx, 8192);
178 #endif
179 if (mem_pool == NULL) {
180 return NULL;
183 parent = talloc(mem_pool, struct smbd_smb2_request *);
184 if (parent == NULL) {
185 talloc_free(mem_pool);
186 return NULL;
189 req = talloc_zero(parent, struct smbd_smb2_request);
190 if (req == NULL) {
191 talloc_free(mem_pool);
192 return NULL;
194 *parent = req;
195 req->mem_pool = mem_pool;
196 req->parent = parent;
198 talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
199 talloc_set_destructor(req, smbd_smb2_request_destructor);
201 return req;
204 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
205 const uint8_t *inbuf, size_t size,
206 struct smbd_smb2_request **_req)
208 struct smbd_smb2_request *req;
209 uint32_t protocol_version;
210 const uint8_t *inhdr = NULL;
211 off_t ofs = 0;
212 uint16_t cmd;
213 uint32_t next_command_ofs;
215 if (size < (4 + SMB2_HDR_BODY + 2)) {
216 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
217 return NT_STATUS_INVALID_PARAMETER;
220 inhdr = inbuf + 4;
222 protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
223 if (protocol_version != SMB2_MAGIC) {
224 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
225 protocol_version));
226 return NT_STATUS_INVALID_PARAMETER;
229 cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
230 if (cmd != SMB2_OP_NEGPROT) {
231 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
232 cmd));
233 return NT_STATUS_INVALID_PARAMETER;
236 next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
237 if (next_command_ofs != 0) {
238 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
239 next_command_ofs));
240 return NT_STATUS_INVALID_PARAMETER;
243 req = smbd_smb2_request_allocate(sconn);
244 if (req == NULL) {
245 return NT_STATUS_NO_MEMORY;
247 req->sconn = sconn;
249 talloc_steal(req, inbuf);
251 req->in.vector = talloc_array(req, struct iovec, 4);
252 if (req->in.vector == NULL) {
253 TALLOC_FREE(req);
254 return NT_STATUS_NO_MEMORY;
256 req->in.vector_count = 4;
258 memcpy(req->in.nbt_hdr, inbuf, 4);
260 ofs = 0;
261 req->in.vector[0].iov_base = (void *)req->in.nbt_hdr;
262 req->in.vector[0].iov_len = 4;
263 ofs += req->in.vector[0].iov_len;
265 req->in.vector[1].iov_base = (void *)(inbuf + ofs);
266 req->in.vector[1].iov_len = SMB2_HDR_BODY;
267 ofs += req->in.vector[1].iov_len;
269 req->in.vector[2].iov_base = (void *)(inbuf + ofs);
270 req->in.vector[2].iov_len = SVAL(inbuf, ofs) & 0xFFFE;
271 ofs += req->in.vector[2].iov_len;
273 if (ofs > size) {
274 return NT_STATUS_INVALID_PARAMETER;
277 req->in.vector[3].iov_base = (void *)(inbuf + ofs);
278 req->in.vector[3].iov_len = size - ofs;
279 ofs += req->in.vector[3].iov_len;
281 req->current_idx = 1;
283 *_req = req;
284 return NT_STATUS_OK;
287 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req,
288 uint16_t *p_creds_requested)
290 int count;
291 int idx;
292 bool compound_related = false;
294 *p_creds_requested = 0;
295 count = req->in.vector_count;
297 if (count < 4) {
298 /* It's not a SMB2 request */
299 return NT_STATUS_INVALID_PARAMETER;
302 for (idx=1; idx < count; idx += 3) {
303 uint16_t creds_requested = 0;
304 const uint8_t *inhdr = NULL;
305 uint32_t flags;
307 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
308 return NT_STATUS_INVALID_PARAMETER;
311 if (req->in.vector[idx+1].iov_len < 2) {
312 return NT_STATUS_INVALID_PARAMETER;
315 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
317 /* setup the SMB2 header */
318 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
319 return NT_STATUS_INVALID_PARAMETER;
322 creds_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
323 if (*p_creds_requested + creds_requested < creds_requested) {
324 *p_creds_requested = 65535;
325 } else {
326 *p_creds_requested += creds_requested;
329 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
330 if (idx == 1) {
332 * the 1st request should never have the
333 * SMB2_HDR_FLAG_CHAINED flag set
335 if (flags & SMB2_HDR_FLAG_CHAINED) {
336 req->next_status = NT_STATUS_INVALID_PARAMETER;
337 return NT_STATUS_OK;
339 } else if (idx == 4) {
341 * the 2nd request triggers related vs. unrelated
342 * compounded requests
344 if (flags & SMB2_HDR_FLAG_CHAINED) {
345 compound_related = true;
347 } else if (idx > 4) {
348 #if 0
350 * It seems the this tests are wrong
351 * see the SMB2-COMPOUND test
355 * all other requests should match the 2nd one
357 if (flags & SMB2_HDR_FLAG_CHAINED) {
358 if (!compound_related) {
359 req->next_status =
360 NT_STATUS_INVALID_PARAMETER;
361 return NT_STATUS_OK;
363 } else {
364 if (compound_related) {
365 req->next_status =
366 NT_STATUS_INVALID_PARAMETER;
367 return NT_STATUS_OK;
370 #endif
374 return NT_STATUS_OK;
377 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req, uint16_t creds)
379 struct iovec *vector;
380 int count;
381 int idx;
383 count = req->in.vector_count;
384 vector = talloc_zero_array(req, struct iovec, count);
385 if (vector == NULL) {
386 return NT_STATUS_NO_MEMORY;
389 vector[0].iov_base = req->out.nbt_hdr;
390 vector[0].iov_len = 4;
391 SIVAL(req->out.nbt_hdr, 0, 0);
393 for (idx=1; idx < count; idx += 3) {
394 const uint8_t *inhdr = NULL;
395 uint32_t in_flags;
396 uint8_t *outhdr = NULL;
397 uint8_t *outbody = NULL;
398 uint32_t next_command_ofs = 0;
399 struct iovec *current = &vector[idx];
401 if ((idx + 3) < count) {
402 /* we have a next command -
403 * setup for the error case. */
404 next_command_ofs = SMB2_HDR_BODY + 9;
407 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
408 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
410 outhdr = talloc_zero_array(vector, uint8_t,
411 OUTVEC_ALLOC_SIZE);
412 if (outhdr == NULL) {
413 return NT_STATUS_NO_MEMORY;
416 outbody = outhdr + SMB2_HDR_BODY;
418 current[0].iov_base = (void *)outhdr;
419 current[0].iov_len = SMB2_HDR_BODY;
421 current[1].iov_base = (void *)outbody;
422 current[1].iov_len = 8;
424 current[2].iov_base = NULL;
425 current[2].iov_len = 0;
427 /* setup the SMB2 header */
428 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
429 SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
430 SSVAL(outhdr, SMB2_HDR_EPOCH, 0);
431 SIVAL(outhdr, SMB2_HDR_STATUS,
432 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
433 SSVAL(outhdr, SMB2_HDR_OPCODE,
434 SVAL(inhdr, SMB2_HDR_OPCODE));
435 SSVAL(outhdr, SMB2_HDR_CREDIT, creds);
437 /* Remember what we gave out. */
438 req->sconn->smb2.credits_granted += creds;
440 SIVAL(outhdr, SMB2_HDR_FLAGS,
441 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
442 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
443 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
444 BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
445 SIVAL(outhdr, SMB2_HDR_PID,
446 IVAL(inhdr, SMB2_HDR_PID));
447 SIVAL(outhdr, SMB2_HDR_TID,
448 IVAL(inhdr, SMB2_HDR_TID));
449 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
450 BVAL(inhdr, SMB2_HDR_SESSION_ID));
451 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
453 /* setup error body header */
454 SSVAL(outbody, 0x00, 0x08 + 1);
455 SSVAL(outbody, 0x02, 0);
456 SIVAL(outbody, 0x04, 0);
459 req->out.vector = vector;
460 req->out.vector_count = count;
462 /* setup the length of the NBT packet */
463 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
465 DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
467 return NT_STATUS_OK;
470 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
471 const char *reason,
472 const char *location)
474 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
475 reason, location));
476 exit_server_cleanly(reason);
479 static bool dup_smb2_vec(struct iovec *dstvec,
480 const struct iovec *srcvec,
481 int offset)
484 if (srcvec[offset].iov_len &&
485 srcvec[offset].iov_base) {
486 dstvec[offset].iov_base = talloc_memdup(dstvec,
487 srcvec[offset].iov_base,
488 srcvec[offset].iov_len);
489 if (!dstvec[offset].iov_base) {
490 return false;
492 dstvec[offset].iov_len = srcvec[offset].iov_len;
493 } else {
494 dstvec[offset].iov_base = NULL;
495 dstvec[offset].iov_len = 0;
497 return true;
500 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
502 struct smbd_smb2_request *newreq = NULL;
503 struct iovec *outvec = NULL;
504 int count = req->out.vector_count;
505 int i;
507 newreq = smbd_smb2_request_allocate(req->sconn);
508 if (!newreq) {
509 return NULL;
512 newreq->sconn = req->sconn;
513 newreq->do_signing = req->do_signing;
514 newreq->current_idx = req->current_idx;
515 newreq->async = false;
516 newreq->cancelled = false;
518 outvec = talloc_zero_array(newreq, struct iovec, count);
519 if (!outvec) {
520 TALLOC_FREE(newreq);
521 return NULL;
523 newreq->out.vector = outvec;
524 newreq->out.vector_count = count;
526 /* Setup the outvec's identically to req. */
527 outvec[0].iov_base = newreq->out.nbt_hdr;
528 outvec[0].iov_len = 4;
529 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
531 for (i = 1; i < count; i += 3) {
532 /* i + 0 and i + 1 are always
533 * boilerplate. */
534 outvec[i].iov_base = talloc_memdup(outvec,
535 req->out.vector[i].iov_base,
536 OUTVEC_ALLOC_SIZE);
537 if (!outvec[i].iov_base) {
538 break;
540 outvec[i].iov_len = SMB2_HDR_BODY;
542 outvec[i+1].iov_base = ((uint8_t *)outvec[i].iov_base) +
543 SMB2_HDR_BODY;
544 outvec[i+1].iov_len = 8;
546 if (req->out.vector[i+2].iov_base ==
547 ((uint8_t *)req->out.vector[i].iov_base) +
548 (OUTVEC_ALLOC_SIZE - 1) &&
549 req->out.vector[i+2].iov_len == 1) {
550 /* Common SMB2 error packet case. */
551 outvec[i+2].iov_base = ((uint8_t *)outvec[i].iov_base) +
552 (OUTVEC_ALLOC_SIZE - 1);
553 outvec[i+2].iov_len = 1;
554 } else if (!dup_smb2_vec(outvec,
555 req->out.vector,
556 i)) {
557 break;
561 if (i < count) {
562 /* Alloc failed. */
563 TALLOC_FREE(newreq);
564 return NULL;
567 smb2_setup_nbt_length(newreq->out.vector,
568 newreq->out.vector_count);
570 return newreq;
573 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
575 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
577 int i = 0;
578 uint8_t *outhdr = NULL;
579 struct smbd_smb2_request *nreq = NULL;
581 /* Create a new smb2 request we'll use
582 for the interim return. */
583 nreq = dup_smb2_req(req);
584 if (!nreq) {
585 return NT_STATUS_NO_MEMORY;
588 /* Lose the last 3 out vectors. They're the
589 ones we'll be using for the async reply. */
590 nreq->out.vector_count -= 3;
592 smb2_setup_nbt_length(nreq->out.vector,
593 nreq->out.vector_count);
595 /* Step back to the previous reply. */
596 i = nreq->current_idx - 3;
597 outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
598 /* And end the chain. */
599 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
601 /* Re-sign if needed. */
602 if (nreq->do_signing) {
603 NTSTATUS status;
604 status = smb2_signing_sign_pdu(nreq->session->session_key,
605 &nreq->out.vector[i], 3);
606 if (!NT_STATUS_IS_OK(status)) {
607 return status;
610 if (DEBUGLEVEL >= 10) {
611 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
612 (unsigned int)nreq->current_idx );
613 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
614 (unsigned int)nreq->out.vector_count );
615 print_req_vectors(nreq);
617 nreq->subreq = tstream_writev_queue_send(nreq,
618 nreq->sconn->smb2.event_ctx,
619 nreq->sconn->smb2.stream,
620 nreq->sconn->smb2.send_queue,
621 nreq->out.vector,
622 nreq->out.vector_count);
624 if (nreq->subreq == NULL) {
625 return NT_STATUS_NO_MEMORY;
628 tevent_req_set_callback(nreq->subreq,
629 smbd_smb2_request_writev_done,
630 nreq);
632 return NT_STATUS_OK;
635 struct smbd_smb2_request_pending_state {
636 struct smbd_server_connection *sconn;
637 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
638 struct iovec vector[3];
641 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
643 struct smbd_smb2_request_pending_state *state =
644 tevent_req_callback_data(subreq,
645 struct smbd_smb2_request_pending_state);
646 struct smbd_server_connection *sconn = state->sconn;
647 int ret;
648 int sys_errno;
650 ret = tstream_writev_queue_recv(subreq, &sys_errno);
651 TALLOC_FREE(subreq);
652 if (ret == -1) {
653 NTSTATUS status = map_nt_error_from_unix(sys_errno);
654 smbd_server_connection_terminate(sconn, nt_errstr(status));
655 return;
658 TALLOC_FREE(state);
661 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
662 struct tevent_req *subreq)
664 NTSTATUS status;
665 struct smbd_smb2_request_pending_state *state = NULL;
666 int i = req->current_idx;
667 uint8_t *reqhdr = NULL;
668 uint8_t *hdr = NULL;
669 uint8_t *body = NULL;
670 uint32_t flags = 0;
671 uint64_t message_id = 0;
672 uint64_t async_id = 0;
673 struct iovec *outvec = NULL;
675 if (!tevent_req_is_in_progress(subreq)) {
676 return NT_STATUS_OK;
679 if (req->async) {
680 /* We're already async. */
681 return NT_STATUS_OK;
684 if (req->in.vector_count > i + 3) {
686 * We're trying to go async in a compound
687 * request chain. This is not allowed.
688 * Cancel the outstanding request.
690 tevent_req_cancel(subreq);
691 return smbd_smb2_request_error(req,
692 NT_STATUS_INSUFFICIENT_RESOURCES);
695 req->subreq = subreq;
696 subreq = NULL;
698 if (DEBUGLEVEL >= 10) {
699 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
700 (unsigned int)req->current_idx );
701 print_req_vectors(req);
704 if (req->out.vector_count > 4) {
705 /* This is a compound reply. We
706 * must do an interim response
707 * followed by the async response
708 * to match W2K8R2.
710 status = smb2_send_async_interim_response(req);
711 if (!NT_STATUS_IS_OK(status)) {
712 return status;
716 /* Don't return an intermediate packet on a pipe read/write. */
717 if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) {
718 return NT_STATUS_OK;
721 reqhdr = (uint8_t *)req->out.vector[i].iov_base;
722 flags = (IVAL(reqhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
723 message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
724 async_id = message_id; /* keep it simple for now... */
727 * What we send is identical to a smbd_smb2_request_error
728 * packet with an error status of STATUS_PENDING. Make use
729 * of this fact sometime when refactoring. JRA.
732 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
733 if (state == NULL) {
734 return NT_STATUS_NO_MEMORY;
736 state->sconn = req->sconn;
738 state->vector[0].iov_base = (void *)state->buf;
739 state->vector[0].iov_len = 4;
741 state->vector[1].iov_base = state->buf + 4;
742 state->vector[1].iov_len = SMB2_HDR_BODY;
744 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
745 state->vector[2].iov_len = 9;
747 smb2_setup_nbt_length(state->vector, 3);
749 hdr = (uint8_t *)state->vector[1].iov_base;
750 body = (uint8_t *)state->vector[2].iov_base;
752 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
753 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
754 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
755 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
756 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
757 SSVAL(hdr, SMB2_HDR_CREDIT, 5);
759 req->sconn->smb2.credits_granted += 5;
761 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
762 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
763 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
764 SBVAL(hdr, SMB2_HDR_PID, async_id);
765 SBVAL(hdr, SMB2_HDR_SESSION_ID,
766 BVAL(reqhdr, SMB2_HDR_SESSION_ID));
767 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
769 SSVAL(body, 0x00, 0x08 + 1);
771 SCVAL(body, 0x02, 0);
772 SCVAL(body, 0x03, 0);
773 SIVAL(body, 0x04, 0);
774 /* Match W2K8R2... */
775 SCVAL(body, 0x08, 0x21);
777 if (req->do_signing) {
778 status = smb2_signing_sign_pdu(req->session->session_key,
779 state->vector, 3);
780 if (!NT_STATUS_IS_OK(status)) {
781 return status;
785 subreq = tstream_writev_queue_send(state,
786 req->sconn->smb2.event_ctx,
787 req->sconn->smb2.stream,
788 req->sconn->smb2.send_queue,
789 state->vector,
792 if (subreq == NULL) {
793 return NT_STATUS_NO_MEMORY;
796 tevent_req_set_callback(subreq,
797 smbd_smb2_request_pending_writev_done,
798 state);
800 /* Note we're going async with this request. */
801 req->async = true;
804 * Now manipulate req so that the outstanding async request
805 * is the only one left in the struct smbd_smb2_request.
808 if (req->current_idx == 1) {
809 /* There was only one. */
810 goto out;
813 /* Re-arrange the in.vectors. */
814 req->in.vector[1] = req->in.vector[i];
815 req->in.vector[2] = req->in.vector[i+1];
816 req->in.vector[3] = req->in.vector[i+2];
817 req->in.vector_count = 4;
818 /* Reset the new in size. */
819 smb2_setup_nbt_length(req->in.vector, 4);
821 /* Now recreate the out.vectors. */
822 outvec = talloc_zero_array(req, struct iovec, 4);
823 if (!outvec) {
824 return NT_STATUS_NO_MEMORY;
826 outvec[0].iov_base = req->out.nbt_hdr;
827 outvec[0].iov_len = 4;
828 SIVAL(req->out.nbt_hdr, 0, 0);
830 outvec[1].iov_base = talloc_memdup(outvec,
831 req->out.vector[i].iov_base,
832 OUTVEC_ALLOC_SIZE);
833 if (!outvec[1].iov_base) {
834 return NT_STATUS_NO_MEMORY;
836 outvec[1].iov_len = SMB2_HDR_BODY;
838 outvec[2].iov_base = ((uint8_t *)outvec[1].iov_base) +
839 SMB2_HDR_BODY;
840 outvec[2].iov_len = 8;
842 if (req->out.vector[i+2].iov_base &&
843 req->out.vector[i+2].iov_len) {
844 if (req->out.vector[i+2].iov_base ==
845 ((uint8_t *)req->out.vector[i].iov_base) +
846 (OUTVEC_ALLOC_SIZE - 1) &&
847 req->out.vector[i].iov_len == 1) {
848 /* Common SMB2 error packet case. */
849 outvec[3].iov_base = ((uint8_t *)outvec[1].iov_base) +
850 (OUTVEC_ALLOC_SIZE - 1);
851 } else {
852 outvec[3].iov_base = talloc_memdup(outvec,
853 req->out.vector[i+2].iov_base,
854 req->out.vector[i+2].iov_len);
855 if (!outvec[3].iov_base) {
856 return NT_STATUS_NO_MEMORY;
859 outvec[3].iov_len = req->out.vector[i+2].iov_len;
860 } else {
861 outvec[3].iov_base = NULL;
862 outvec[3].iov_len = 0;
865 TALLOC_FREE(req->out.vector);
867 req->out.vector = outvec;
869 req->current_idx = 1;
870 req->out.vector_count = 4;
872 out:
874 smb2_setup_nbt_length(req->out.vector,
875 req->out.vector_count);
877 /* Ensure our final reply matches the interim one. */
878 reqhdr = (uint8_t *)req->out.vector[1].iov_base;
879 SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
880 SBVAL(reqhdr, SMB2_HDR_PID, async_id);
883 const uint8_t *inhdr =
884 (const uint8_t *)req->in.vector[1].iov_base;
885 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
886 "going async\n",
887 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
888 (unsigned long long)async_id ));
890 return NT_STATUS_OK;
893 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
895 struct smbd_server_connection *sconn = req->sconn;
896 struct smbd_smb2_request *cur;
897 const uint8_t *inhdr;
898 int i = req->current_idx;
899 uint32_t flags;
900 uint64_t search_message_id;
901 uint64_t search_async_id;
902 uint64_t found_id;
904 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
906 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
907 search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
908 search_async_id = BVAL(inhdr, SMB2_HDR_PID);
911 * we don't need the request anymore
912 * cancel requests never have a response
914 DLIST_REMOVE(req->sconn->smb2.requests, req);
915 TALLOC_FREE(req);
917 for (cur = sconn->smb2.requests; cur; cur = cur->next) {
918 const uint8_t *outhdr;
919 uint64_t message_id;
920 uint64_t async_id;
922 i = cur->current_idx;
924 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
926 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
927 async_id = BVAL(outhdr, SMB2_HDR_PID);
929 if (flags & SMB2_HDR_FLAG_ASYNC) {
930 if (search_async_id == async_id) {
931 found_id = async_id;
932 break;
934 } else {
935 if (search_message_id == message_id) {
936 found_id = message_id;
937 break;
942 if (cur && cur->subreq) {
943 inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
944 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
945 "cancel opcode[%s] mid %llu\n",
946 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
947 (unsigned long long)found_id ));
948 tevent_req_cancel(cur->subreq);
951 return NT_STATUS_OK;
954 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
956 const uint8_t *inhdr;
957 int i = req->current_idx;
958 uint16_t opcode;
959 uint32_t flags;
960 uint64_t mid;
961 NTSTATUS status;
962 NTSTATUS session_status;
963 uint32_t allowed_flags;
965 inhdr = (const uint8_t *)req->in.vector[i].iov_base;
967 /* TODO: verify more things */
969 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
970 opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
971 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
972 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
973 smb2_opcode_name(opcode),
974 (unsigned long long)mid));
976 allowed_flags = SMB2_HDR_FLAG_CHAINED |
977 SMB2_HDR_FLAG_SIGNED |
978 SMB2_HDR_FLAG_DFS;
979 if (opcode == SMB2_OP_CANCEL) {
980 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
982 if ((flags & ~allowed_flags) != 0) {
983 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
986 session_status = smbd_smb2_request_check_session(req);
988 req->do_signing = false;
989 if (flags & SMB2_HDR_FLAG_SIGNED) {
990 if (!NT_STATUS_IS_OK(session_status)) {
991 return smbd_smb2_request_error(req, session_status);
994 req->do_signing = true;
995 status = smb2_signing_check_pdu(req->session->session_key,
996 &req->in.vector[i], 3);
997 if (!NT_STATUS_IS_OK(status)) {
998 return smbd_smb2_request_error(req, status);
1000 } else if (req->session && req->session->do_signing) {
1001 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
1004 if (flags & SMB2_HDR_FLAG_CHAINED) {
1006 * This check is mostly for giving the correct error code
1007 * for compounded requests.
1009 * TODO: we may need to move this after the session
1010 * and tcon checks.
1012 if (!NT_STATUS_IS_OK(req->next_status)) {
1013 return smbd_smb2_request_error(req, req->next_status);
1015 } else {
1016 req->compat_chain_fsp = NULL;
1019 switch (opcode) {
1020 case SMB2_OP_NEGPROT:
1021 return smbd_smb2_request_process_negprot(req);
1023 case SMB2_OP_SESSSETUP:
1024 return smbd_smb2_request_process_sesssetup(req);
1026 case SMB2_OP_LOGOFF:
1027 if (!NT_STATUS_IS_OK(session_status)) {
1028 return smbd_smb2_request_error(req, session_status);
1030 return smbd_smb2_request_process_logoff(req);
1032 case SMB2_OP_TCON:
1033 if (!NT_STATUS_IS_OK(session_status)) {
1034 return smbd_smb2_request_error(req, session_status);
1036 status = smbd_smb2_request_check_session(req);
1037 if (!NT_STATUS_IS_OK(status)) {
1038 return smbd_smb2_request_error(req, status);
1040 return smbd_smb2_request_process_tcon(req);
1042 case SMB2_OP_TDIS:
1043 if (!NT_STATUS_IS_OK(session_status)) {
1044 return smbd_smb2_request_error(req, session_status);
1046 status = smbd_smb2_request_check_tcon(req);
1047 if (!NT_STATUS_IS_OK(status)) {
1048 return smbd_smb2_request_error(req, status);
1050 return smbd_smb2_request_process_tdis(req);
1052 case SMB2_OP_CREATE:
1053 if (!NT_STATUS_IS_OK(session_status)) {
1054 return smbd_smb2_request_error(req, session_status);
1056 status = smbd_smb2_request_check_tcon(req);
1057 if (!NT_STATUS_IS_OK(status)) {
1058 return smbd_smb2_request_error(req, status);
1060 return smbd_smb2_request_process_create(req);
1062 case SMB2_OP_CLOSE:
1063 if (!NT_STATUS_IS_OK(session_status)) {
1064 return smbd_smb2_request_error(req, session_status);
1066 status = smbd_smb2_request_check_tcon(req);
1067 if (!NT_STATUS_IS_OK(status)) {
1068 return smbd_smb2_request_error(req, status);
1070 return smbd_smb2_request_process_close(req);
1072 case SMB2_OP_FLUSH:
1073 if (!NT_STATUS_IS_OK(session_status)) {
1074 return smbd_smb2_request_error(req, session_status);
1076 status = smbd_smb2_request_check_tcon(req);
1077 if (!NT_STATUS_IS_OK(status)) {
1078 return smbd_smb2_request_error(req, status);
1080 return smbd_smb2_request_process_flush(req);
1082 case SMB2_OP_READ:
1083 if (!NT_STATUS_IS_OK(session_status)) {
1084 return smbd_smb2_request_error(req, session_status);
1086 status = smbd_smb2_request_check_tcon(req);
1087 if (!NT_STATUS_IS_OK(status)) {
1088 return smbd_smb2_request_error(req, status);
1090 return smbd_smb2_request_process_read(req);
1092 case SMB2_OP_WRITE:
1093 if (!NT_STATUS_IS_OK(session_status)) {
1094 return smbd_smb2_request_error(req, session_status);
1096 status = smbd_smb2_request_check_tcon(req);
1097 if (!NT_STATUS_IS_OK(status)) {
1098 return smbd_smb2_request_error(req, status);
1100 return smbd_smb2_request_process_write(req);
1102 case SMB2_OP_LOCK:
1103 if (!NT_STATUS_IS_OK(session_status)) {
1104 /* Too ugly to live ? JRA. */
1105 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
1106 session_status = NT_STATUS_FILE_CLOSED;
1108 return smbd_smb2_request_error(req, session_status);
1110 status = smbd_smb2_request_check_tcon(req);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 /* Too ugly to live ? JRA. */
1113 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
1114 status = NT_STATUS_FILE_CLOSED;
1116 return smbd_smb2_request_error(req, status);
1118 return smbd_smb2_request_process_lock(req);
1120 case SMB2_OP_IOCTL:
1121 if (!NT_STATUS_IS_OK(session_status)) {
1122 return smbd_smb2_request_error(req, session_status);
1124 status = smbd_smb2_request_check_tcon(req);
1125 if (!NT_STATUS_IS_OK(status)) {
1126 return smbd_smb2_request_error(req, status);
1128 return smbd_smb2_request_process_ioctl(req);
1130 case SMB2_OP_CANCEL:
1131 return smbd_smb2_request_process_cancel(req);
1133 case SMB2_OP_KEEPALIVE:
1134 return smbd_smb2_request_process_keepalive(req);
1136 case SMB2_OP_FIND:
1137 if (!NT_STATUS_IS_OK(session_status)) {
1138 return smbd_smb2_request_error(req, session_status);
1140 status = smbd_smb2_request_check_tcon(req);
1141 if (!NT_STATUS_IS_OK(status)) {
1142 return smbd_smb2_request_error(req, status);
1144 return smbd_smb2_request_process_find(req);
1146 case SMB2_OP_NOTIFY:
1147 if (!NT_STATUS_IS_OK(session_status)) {
1148 return smbd_smb2_request_error(req, session_status);
1150 status = smbd_smb2_request_check_tcon(req);
1151 if (!NT_STATUS_IS_OK(status)) {
1152 return smbd_smb2_request_error(req, status);
1154 return smbd_smb2_request_process_notify(req);
1156 case SMB2_OP_GETINFO:
1157 if (!NT_STATUS_IS_OK(session_status)) {
1158 return smbd_smb2_request_error(req, session_status);
1160 status = smbd_smb2_request_check_tcon(req);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 return smbd_smb2_request_error(req, status);
1164 return smbd_smb2_request_process_getinfo(req);
1166 case SMB2_OP_SETINFO:
1167 if (!NT_STATUS_IS_OK(session_status)) {
1168 return smbd_smb2_request_error(req, session_status);
1170 status = smbd_smb2_request_check_tcon(req);
1171 if (!NT_STATUS_IS_OK(status)) {
1172 return smbd_smb2_request_error(req, status);
1174 return smbd_smb2_request_process_setinfo(req);
1176 case SMB2_OP_BREAK:
1177 if (!NT_STATUS_IS_OK(session_status)) {
1178 return smbd_smb2_request_error(req, session_status);
1180 status = smbd_smb2_request_check_tcon(req);
1181 if (!NT_STATUS_IS_OK(status)) {
1182 return smbd_smb2_request_error(req, status);
1184 return smbd_smb2_request_process_break(req);
1187 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1190 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
1192 struct tevent_req *subreq;
1194 req->subreq = NULL;
1196 smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
1198 if (req->do_signing) {
1199 int i = req->current_idx;
1200 NTSTATUS status;
1201 status = smb2_signing_sign_pdu(req->session->session_key,
1202 &req->out.vector[i], 3);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 return status;
1208 req->current_idx += 3;
1210 if (req->current_idx < req->out.vector_count) {
1212 * We must process the remaining compound
1213 * SMB2 requests before any new incoming SMB2
1214 * requests. This is because incoming SMB2
1215 * requests may include a cancel for a
1216 * compound request we haven't processed
1217 * yet.
1219 struct tevent_immediate *im = tevent_create_immediate(req);
1220 if (!im) {
1221 return NT_STATUS_NO_MEMORY;
1223 tevent_schedule_immediate(im,
1224 req->sconn->smb2.event_ctx,
1225 smbd_smb2_request_dispatch_immediate,
1226 req);
1227 return NT_STATUS_OK;
1230 if (DEBUGLEVEL >= 10) {
1231 dbgtext("smbd_smb2_request_reply: sending...\n");
1232 print_req_vectors(req);
1235 subreq = tstream_writev_queue_send(req,
1236 req->sconn->smb2.event_ctx,
1237 req->sconn->smb2.stream,
1238 req->sconn->smb2.send_queue,
1239 req->out.vector,
1240 req->out.vector_count);
1241 if (subreq == NULL) {
1242 return NT_STATUS_NO_MEMORY;
1244 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
1246 * We're done with this request -
1247 * move it off the "being processed" queue.
1249 DLIST_REMOVE(req->sconn->smb2.requests, req);
1251 return NT_STATUS_OK;
1254 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
1255 struct tevent_immediate *im,
1256 void *private_data)
1258 struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
1259 struct smbd_smb2_request);
1260 struct smbd_server_connection *sconn = req->sconn;
1261 NTSTATUS status;
1263 TALLOC_FREE(im);
1265 if (DEBUGLEVEL >= 10) {
1266 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
1267 req->current_idx, req->in.vector_count));
1268 print_req_vectors(req);
1271 status = smbd_smb2_request_dispatch(req);
1272 if (!NT_STATUS_IS_OK(status)) {
1273 smbd_server_connection_terminate(sconn, nt_errstr(status));
1274 return;
1278 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
1280 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
1281 struct smbd_smb2_request);
1282 struct smbd_server_connection *sconn = req->sconn;
1283 int ret;
1284 int sys_errno;
1286 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1287 TALLOC_FREE(subreq);
1288 TALLOC_FREE(req);
1289 if (ret == -1) {
1290 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1291 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
1292 nt_errstr(status)));
1293 smbd_server_connection_terminate(sconn, nt_errstr(status));
1294 return;
1298 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
1299 NTSTATUS status,
1300 DATA_BLOB body, DATA_BLOB *dyn,
1301 const char *location)
1303 uint8_t *outhdr;
1304 int i = req->current_idx;
1305 uint32_t next_command_ofs;
1307 DEBUG(10,("smbd_smb2_request_done_ex: "
1308 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
1309 i, nt_errstr(status), (unsigned int)body.length,
1310 dyn ? "yes": "no",
1311 (unsigned int)(dyn ? dyn->length : 0),
1312 location));
1314 if (body.length < 2) {
1315 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1318 if ((body.length % 2) != 0) {
1319 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
1322 outhdr = (uint8_t *)req->out.vector[i].iov_base;
1324 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
1325 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
1327 req->out.vector[i+1].iov_base = (void *)body.data;
1328 req->out.vector[i+1].iov_len = body.length;
1330 if (dyn) {
1331 req->out.vector[i+2].iov_base = (void *)dyn->data;
1332 req->out.vector[i+2].iov_len = dyn->length;
1333 } else {
1334 req->out.vector[i+2].iov_base = NULL;
1335 req->out.vector[i+2].iov_len = 0;
1338 /* see if we need to recalculate the offset to the next response */
1339 if (next_command_ofs > 0) {
1340 next_command_ofs = SMB2_HDR_BODY;
1341 next_command_ofs += req->out.vector[i+1].iov_len;
1342 next_command_ofs += req->out.vector[i+2].iov_len;
1345 if ((next_command_ofs % 8) != 0) {
1346 size_t pad_size = 8 - (next_command_ofs % 8);
1347 if (req->out.vector[i+2].iov_len == 0) {
1349 * if the dyn buffer is empty
1350 * we can use it to add padding
1352 uint8_t *pad;
1354 pad = talloc_zero_array(req->out.vector,
1355 uint8_t, pad_size);
1356 if (pad == NULL) {
1357 return smbd_smb2_request_error(req,
1358 NT_STATUS_NO_MEMORY);
1361 req->out.vector[i+2].iov_base = (void *)pad;
1362 req->out.vector[i+2].iov_len = pad_size;
1363 } else {
1365 * For now we copy the dynamic buffer
1366 * and add the padding to the new buffer
1368 size_t old_size;
1369 uint8_t *old_dyn;
1370 size_t new_size;
1371 uint8_t *new_dyn;
1373 old_size = req->out.vector[i+2].iov_len;
1374 old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
1376 new_size = old_size + pad_size;
1377 new_dyn = talloc_zero_array(req->out.vector,
1378 uint8_t, new_size);
1379 if (new_dyn == NULL) {
1380 return smbd_smb2_request_error(req,
1381 NT_STATUS_NO_MEMORY);
1384 memcpy(new_dyn, old_dyn, old_size);
1385 memset(new_dyn + old_size, 0, pad_size);
1387 req->out.vector[i+2].iov_base = (void *)new_dyn;
1388 req->out.vector[i+2].iov_len = new_size;
1390 next_command_ofs += pad_size;
1393 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1395 return smbd_smb2_request_reply(req);
1398 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
1399 NTSTATUS status,
1400 DATA_BLOB *info,
1401 const char *location)
1403 DATA_BLOB body;
1404 int i = req->current_idx;
1405 uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
1407 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
1408 i, nt_errstr(status), info ? " +info" : "",
1409 location));
1411 body.data = outhdr + SMB2_HDR_BODY;
1412 body.length = 8;
1413 SSVAL(body.data, 0, 9);
1415 if (info) {
1416 SIVAL(body.data, 0x04, info->length);
1417 } else {
1418 /* Allocated size of req->out.vector[i].iov_base
1419 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
1420 * 1 byte without having to do an alloc.
1422 info = talloc_zero_array(req->out.vector,
1423 DATA_BLOB,
1425 if (!info) {
1426 return NT_STATUS_NO_MEMORY;
1428 info->data = ((uint8_t *)outhdr) +
1429 OUTVEC_ALLOC_SIZE - 1;
1430 info->length = 1;
1431 SCVAL(info->data, 0, 0);
1435 * if a request fails, all other remaining
1436 * compounded requests should fail too
1438 req->next_status = NT_STATUS_INVALID_PARAMETER;
1440 return smbd_smb2_request_done_ex(req, status, body, info, __location__);
1444 struct smbd_smb2_send_oplock_break_state {
1445 struct smbd_server_connection *sconn;
1446 uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
1447 struct iovec vector;
1450 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
1452 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
1453 uint64_t file_id_persistent,
1454 uint64_t file_id_volatile,
1455 uint8_t oplock_level)
1457 struct smbd_smb2_send_oplock_break_state *state;
1458 struct tevent_req *subreq;
1459 uint8_t *hdr;
1460 uint8_t *body;
1462 state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
1463 if (state == NULL) {
1464 return NT_STATUS_NO_MEMORY;
1466 state->sconn = sconn;
1468 state->vector.iov_base = (void *)state->buf;
1469 state->vector.iov_len = sizeof(state->buf);
1471 _smb2_setlen(state->buf, sizeof(state->buf) - 4);
1472 hdr = state->buf + 4;
1473 body = hdr + SMB2_HDR_BODY;
1475 SIVAL(hdr, 0, SMB2_MAGIC);
1476 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
1477 SSVAL(hdr, SMB2_HDR_EPOCH, 0);
1478 SIVAL(hdr, SMB2_HDR_STATUS, 0);
1479 SSVAL(hdr, SMB2_HDR_OPCODE, SMB2_OP_BREAK);
1480 SSVAL(hdr, SMB2_HDR_CREDIT, 0);
1481 SIVAL(hdr, SMB2_HDR_FLAGS, SMB2_HDR_FLAG_REDIRECT);
1482 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
1483 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
1484 SIVAL(hdr, SMB2_HDR_PID, 0);
1485 SIVAL(hdr, SMB2_HDR_TID, 0);
1486 SBVAL(hdr, SMB2_HDR_SESSION_ID, 0);
1487 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
1489 SSVAL(body, 0x00, 0x18);
1491 SCVAL(body, 0x02, oplock_level);
1492 SCVAL(body, 0x03, 0); /* reserved */
1493 SIVAL(body, 0x04, 0); /* reserved */
1494 SBVAL(body, 0x08, file_id_persistent);
1495 SBVAL(body, 0x10, file_id_volatile);
1497 subreq = tstream_writev_queue_send(state,
1498 sconn->smb2.event_ctx,
1499 sconn->smb2.stream,
1500 sconn->smb2.send_queue,
1501 &state->vector, 1);
1502 if (subreq == NULL) {
1503 return NT_STATUS_NO_MEMORY;
1505 tevent_req_set_callback(subreq,
1506 smbd_smb2_oplock_break_writev_done,
1507 state);
1509 return NT_STATUS_OK;
1512 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
1514 struct smbd_smb2_send_oplock_break_state *state =
1515 tevent_req_callback_data(subreq,
1516 struct smbd_smb2_send_oplock_break_state);
1517 struct smbd_server_connection *sconn = state->sconn;
1518 int ret;
1519 int sys_errno;
1521 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1522 TALLOC_FREE(subreq);
1523 if (ret == -1) {
1524 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1525 smbd_server_connection_terminate(sconn, nt_errstr(status));
1526 return;
1529 TALLOC_FREE(state);
1532 struct smbd_smb2_request_read_state {
1533 size_t missing;
1534 bool asked_for_header;
1535 struct smbd_smb2_request *smb2_req;
1538 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1539 void *private_data,
1540 TALLOC_CTX *mem_ctx,
1541 struct iovec **_vector,
1542 size_t *_count);
1543 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
1545 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
1546 struct tevent_context *ev,
1547 struct smbd_server_connection *sconn)
1549 struct tevent_req *req;
1550 struct smbd_smb2_request_read_state *state;
1551 struct tevent_req *subreq;
1553 req = tevent_req_create(mem_ctx, &state,
1554 struct smbd_smb2_request_read_state);
1555 if (req == NULL) {
1556 return NULL;
1558 state->missing = 0;
1559 state->asked_for_header = false;
1561 state->smb2_req = smbd_smb2_request_allocate(state);
1562 if (tevent_req_nomem(state->smb2_req, req)) {
1563 return tevent_req_post(req, ev);
1565 state->smb2_req->sconn = sconn;
1567 subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
1568 sconn->smb2.recv_queue,
1569 smbd_smb2_request_next_vector,
1570 state);
1571 if (tevent_req_nomem(subreq, req)) {
1572 return tevent_req_post(req, ev);
1574 tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
1576 return req;
1579 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1580 void *private_data,
1581 TALLOC_CTX *mem_ctx,
1582 struct iovec **_vector,
1583 size_t *_count)
1585 struct smbd_smb2_request_read_state *state =
1586 talloc_get_type_abort(private_data,
1587 struct smbd_smb2_request_read_state);
1588 struct smbd_smb2_request *req = state->smb2_req;
1589 struct iovec *vector;
1590 int idx = req->in.vector_count;
1591 size_t len = 0;
1592 uint8_t *buf = NULL;
1594 if (req->in.vector_count == 0) {
1596 * first we need to get the NBT header
1598 req->in.vector = talloc_array(req, struct iovec,
1599 req->in.vector_count + 1);
1600 if (req->in.vector == NULL) {
1601 return -1;
1603 req->in.vector_count += 1;
1605 req->in.vector[idx].iov_base = (void *)req->in.nbt_hdr;
1606 req->in.vector[idx].iov_len = 4;
1608 vector = talloc_array(mem_ctx, struct iovec, 1);
1609 if (vector == NULL) {
1610 return -1;
1613 vector[0] = req->in.vector[idx];
1615 *_vector = vector;
1616 *_count = 1;
1617 return 0;
1620 if (req->in.vector_count == 1) {
1622 * Now we analyze the NBT header
1624 state->missing = smb2_len(req->in.vector[0].iov_base);
1626 if (state->missing == 0) {
1627 /* if there're no remaining bytes, we're done */
1628 *_vector = NULL;
1629 *_count = 0;
1630 return 0;
1633 req->in.vector = talloc_realloc(req, req->in.vector,
1634 struct iovec,
1635 req->in.vector_count + 1);
1636 if (req->in.vector == NULL) {
1637 return -1;
1639 req->in.vector_count += 1;
1641 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
1643 * it's a special NBT message,
1644 * so get all remaining bytes
1646 len = state->missing;
1647 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
1649 * it's an invalid message, just read what we can get
1650 * and let the caller handle the error
1652 len = state->missing;
1653 } else {
1655 * We assume it's a SMB2 request,
1656 * and we first get the header and the
1657 * first 2 bytes (the struct size) of the body
1659 len = SMB2_HDR_BODY + 2;
1661 state->asked_for_header = true;
1664 state->missing -= len;
1666 buf = talloc_array(req->in.vector, uint8_t, len);
1667 if (buf == NULL) {
1668 return -1;
1671 req->in.vector[idx].iov_base = (void *)buf;
1672 req->in.vector[idx].iov_len = len;
1674 vector = talloc_array(mem_ctx, struct iovec, 1);
1675 if (vector == NULL) {
1676 return -1;
1679 vector[0] = req->in.vector[idx];
1681 *_vector = vector;
1682 *_count = 1;
1683 return 0;
1686 if (state->missing == 0) {
1687 /* if there're no remaining bytes, we're done */
1688 *_vector = NULL;
1689 *_count = 0;
1690 return 0;
1693 if (state->asked_for_header) {
1694 const uint8_t *hdr;
1695 size_t full_size;
1696 size_t next_command_ofs;
1697 size_t body_size;
1698 uint8_t *body;
1699 size_t dyn_size;
1700 uint8_t *dyn;
1701 bool invalid = false;
1703 state->asked_for_header = false;
1706 * We got the SMB2 header and the first 2 bytes
1707 * of the body. We fix the size to just the header
1708 * and manually copy the 2 first bytes to the body section
1710 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
1711 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
1713 /* allocate vectors for body and dynamic areas */
1714 req->in.vector = talloc_realloc(req, req->in.vector,
1715 struct iovec,
1716 req->in.vector_count + 2);
1717 if (req->in.vector == NULL) {
1718 return -1;
1720 req->in.vector_count += 2;
1722 full_size = state->missing + SMB2_HDR_BODY + 2;
1723 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
1724 body_size = SVAL(hdr, SMB2_HDR_BODY);
1726 if (next_command_ofs != 0) {
1727 if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
1729 * this is invalid, just return a zero
1730 * body and let the caller deal with the error
1732 invalid = true;
1733 } else if (next_command_ofs > full_size) {
1735 * this is invalid, just return a zero
1736 * body and let the caller deal with the error
1738 invalid = true;
1739 } else {
1740 full_size = next_command_ofs;
1744 if (!invalid) {
1745 if (body_size < 2) {
1747 * this is invalid, just return a zero
1748 * body and let the caller deal with the error
1750 invalid = true;
1753 if ((body_size % 2) != 0) {
1754 body_size -= 1;
1757 if (body_size > (full_size - SMB2_HDR_BODY)) {
1759 * this is invalid, just return a zero
1760 * body and let the caller deal with the error
1762 invalid = true;
1766 if (invalid) {
1767 /* the caller should check this */
1768 body_size = 2;
1771 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
1773 state->missing -= (body_size - 2) + dyn_size;
1775 body = talloc_array(req->in.vector, uint8_t, body_size);
1776 if (body == NULL) {
1777 return -1;
1780 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
1781 if (dyn == NULL) {
1782 return -1;
1785 req->in.vector[idx].iov_base = (void *)body;
1786 req->in.vector[idx].iov_len = body_size;
1787 req->in.vector[idx+1].iov_base = (void *)dyn;
1788 req->in.vector[idx+1].iov_len = dyn_size;
1790 vector = talloc_array(mem_ctx, struct iovec, 2);
1791 if (vector == NULL) {
1792 return -1;
1796 * the first 2 bytes of the body were already fetched
1797 * together with the header
1799 memcpy(body, hdr + SMB2_HDR_BODY, 2);
1800 vector[0].iov_base = body + 2;
1801 vector[0].iov_len = body_size - 2;
1803 vector[1] = req->in.vector[idx+1];
1805 *_vector = vector;
1806 *_count = 2;
1807 return 0;
1811 * when we endup here, we're looking for a new SMB2 request
1812 * next. And we ask for its header and the first 2 bytes of
1813 * the body (like we did for the first SMB2 request).
1816 req->in.vector = talloc_realloc(req, req->in.vector,
1817 struct iovec,
1818 req->in.vector_count + 1);
1819 if (req->in.vector == NULL) {
1820 return -1;
1822 req->in.vector_count += 1;
1825 * We assume it's a SMB2 request,
1826 * and we first get the header and the
1827 * first 2 bytes (the struct size) of the body
1829 len = SMB2_HDR_BODY + 2;
1831 if (len > state->missing) {
1832 /* let the caller handle the error */
1833 len = state->missing;
1836 state->missing -= len;
1837 state->asked_for_header = true;
1839 buf = talloc_array(req->in.vector, uint8_t, len);
1840 if (buf == NULL) {
1841 return -1;
1844 req->in.vector[idx].iov_base = (void *)buf;
1845 req->in.vector[idx].iov_len = len;
1847 vector = talloc_array(mem_ctx, struct iovec, 1);
1848 if (vector == NULL) {
1849 return -1;
1852 vector[0] = req->in.vector[idx];
1854 *_vector = vector;
1855 *_count = 1;
1856 return 0;
1859 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
1861 struct tevent_req *req =
1862 tevent_req_callback_data(subreq,
1863 struct tevent_req);
1864 int ret;
1865 int sys_errno;
1866 NTSTATUS status;
1868 ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1869 if (ret == -1) {
1870 status = map_nt_error_from_unix(sys_errno);
1871 tevent_req_nterror(req, status);
1872 return;
1875 tevent_req_done(req);
1878 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
1879 TALLOC_CTX *mem_ctx,
1880 struct smbd_smb2_request **_smb2_req)
1882 struct smbd_smb2_request_read_state *state =
1883 tevent_req_data(req,
1884 struct smbd_smb2_request_read_state);
1885 NTSTATUS status;
1887 if (tevent_req_is_nterror(req, &status)) {
1888 tevent_req_received(req);
1889 return status;
1892 talloc_steal(mem_ctx, state->smb2_req->mem_pool);
1893 *_smb2_req = state->smb2_req;
1894 tevent_req_received(req);
1895 return NT_STATUS_OK;
1898 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
1900 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
1901 const uint8_t *inbuf, size_t size)
1903 NTSTATUS status;
1904 struct smbd_smb2_request *req;
1905 struct tevent_req *subreq;
1907 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
1908 (unsigned int)size));
1910 status = smbd_initialize_smb2(sconn);
1911 if (!NT_STATUS_IS_OK(status)) {
1912 smbd_server_connection_terminate(sconn, nt_errstr(status));
1913 return;
1916 status = smbd_smb2_request_create(sconn, inbuf, size, &req);
1917 if (!NT_STATUS_IS_OK(status)) {
1918 smbd_server_connection_terminate(sconn, nt_errstr(status));
1919 return;
1922 status = smbd_smb2_request_setup_out(req, 1);
1923 if (!NT_STATUS_IS_OK(status)) {
1924 smbd_server_connection_terminate(sconn, nt_errstr(status));
1925 return;
1928 status = smbd_smb2_request_dispatch(req);
1929 if (!NT_STATUS_IS_OK(status)) {
1930 smbd_server_connection_terminate(sconn, nt_errstr(status));
1931 return;
1934 /* ask for the next request */
1935 subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
1936 if (subreq == NULL) {
1937 smbd_server_connection_terminate(sconn, "no memory for reading");
1938 return;
1940 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
1943 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
1945 uint16_t creds_requested = 0;
1946 struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
1947 struct smbd_server_connection);
1948 NTSTATUS status;
1949 struct smbd_smb2_request *req = NULL;
1951 status = smbd_smb2_request_read_recv(subreq, sconn, &req);
1952 TALLOC_FREE(subreq);
1953 if (!NT_STATUS_IS_OK(status)) {
1954 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
1955 nt_errstr(status)));
1956 smbd_server_connection_terminate(sconn, nt_errstr(status));
1957 return;
1960 if (req->in.nbt_hdr[0] != 0x00) {
1961 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
1962 req->in.nbt_hdr[0]));
1963 TALLOC_FREE(req);
1964 goto next;
1967 req->current_idx = 1;
1969 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
1970 req->current_idx, req->in.vector_count));
1972 status = smbd_smb2_request_validate(req, &creds_requested);
1973 if (!NT_STATUS_IS_OK(status)) {
1974 smbd_server_connection_terminate(sconn, nt_errstr(status));
1975 return;
1978 status = smbd_smb2_request_setup_out(req, 5);
1979 if (!NT_STATUS_IS_OK(status)) {
1980 smbd_server_connection_terminate(sconn, nt_errstr(status));
1981 return;
1984 status = smbd_smb2_request_dispatch(req);
1985 if (!NT_STATUS_IS_OK(status)) {
1986 smbd_server_connection_terminate(sconn, nt_errstr(status));
1987 return;
1990 next:
1991 /* ask for the next request (this constructs the main loop) */
1992 subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
1993 if (subreq == NULL) {
1994 smbd_server_connection_terminate(sconn, "no memory for reading");
1995 return;
1997 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);