2 Unix SMB/CIFS implementation.
5 Copyright (C) Stefan Metzmacher 2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "smbd/globals.h"
23 #include "../libcli/smb/smb_common.h"
24 #include "../lib/tsocket/tsocket.h"
26 static const char *smb2_names
[] = {
48 const char *smb2_opcode_name(uint16_t opcode
)
51 return "Bad SMB2 opcode";
53 return smb2_names
[opcode
];
56 static void print_req_vectors(struct smbd_smb2_request
*req
)
60 for (i
= 0; i
< req
->in
.vector_count
; i
++) {
61 dbgtext("\treq->in.vector[%u].iov_len = %u\n",
63 (unsigned int)req
->in
.vector
[i
].iov_len
);
65 for (i
= 0; i
< req
->out
.vector_count
; i
++) {
66 dbgtext("\treq->out.vector[%u].iov_len = %u\n",
68 (unsigned int)req
->out
.vector
[i
].iov_len
);
72 bool smbd_is_smb2_header(const uint8_t *inbuf
, size_t size
)
74 if (size
< (4 + SMB2_HDR_BODY
)) {
78 if (IVAL(inbuf
, 4) != SMB2_MAGIC
) {
85 static NTSTATUS
smbd_initialize_smb2(struct smbd_server_connection
*sconn
)
90 TALLOC_FREE(sconn
->smb1
.fde
);
92 sconn
->smb2
.event_ctx
= smbd_event_context();
94 sconn
->smb2
.recv_queue
= tevent_queue_create(sconn
, "smb2 recv queue");
95 if (sconn
->smb2
.recv_queue
== NULL
) {
96 return NT_STATUS_NO_MEMORY
;
99 sconn
->smb2
.send_queue
= tevent_queue_create(sconn
, "smb2 send queue");
100 if (sconn
->smb2
.send_queue
== NULL
) {
101 return NT_STATUS_NO_MEMORY
;
104 sconn
->smb2
.sessions
.idtree
= idr_init(sconn
);
105 if (sconn
->smb2
.sessions
.idtree
== NULL
) {
106 return NT_STATUS_NO_MEMORY
;
108 sconn
->smb2
.sessions
.limit
= 0x0000FFFE;
109 sconn
->smb2
.sessions
.list
= NULL
;
111 ret
= tstream_bsd_existing_socket(sconn
, smbd_server_fd(),
112 &sconn
->smb2
.stream
);
114 status
= map_nt_error_from_unix(errno
);
118 /* Ensure child is set to non-blocking mode */
119 set_blocking(smbd_server_fd(),false);
123 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
124 #define _smb2_setlen(_buf,len) do { \
125 uint8_t *buf = (uint8_t *)_buf; \
127 buf[1] = ((len)&0xFF0000)>>16; \
128 buf[2] = ((len)&0xFF00)>>8; \
129 buf[3] = (len)&0xFF; \
132 static void smb2_setup_nbt_length(struct iovec
*vector
, int count
)
137 for (i
=1; i
< count
; i
++) {
138 len
+= vector
[i
].iov_len
;
141 _smb2_setlen(vector
[0].iov_base
, len
);
144 static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request
**req
)
147 (*req
)->parent
= NULL
;
148 (*req
)->mem_pool
= NULL
;
154 static int smbd_smb2_request_destructor(struct smbd_smb2_request
*req
)
156 if (req
->out
.vector
) {
157 DLIST_REMOVE(req
->sconn
->smb2
.requests
, req
);
162 talloc_free(req
->mem_pool
);
168 static struct smbd_smb2_request
*smbd_smb2_request_allocate(TALLOC_CTX
*mem_ctx
)
170 TALLOC_CTX
*mem_pool
;
171 struct smbd_smb2_request
**parent
;
172 struct smbd_smb2_request
*req
;
174 mem_pool
= talloc_pool(mem_ctx
, 8192);
175 if (mem_pool
== NULL
) {
179 parent
= talloc(mem_pool
, struct smbd_smb2_request
*);
180 if (parent
== NULL
) {
181 talloc_free(mem_pool
);
185 req
= talloc_zero(parent
, struct smbd_smb2_request
);
187 talloc_free(mem_pool
);
191 req
->mem_pool
= mem_pool
;
192 req
->parent
= parent
;
194 talloc_set_destructor(parent
, smbd_smb2_request_parent_destructor
);
195 talloc_set_destructor(req
, smbd_smb2_request_destructor
);
200 static NTSTATUS
smbd_smb2_request_create(struct smbd_server_connection
*sconn
,
201 const uint8_t *inbuf
, size_t size
,
202 struct smbd_smb2_request
**_req
)
204 struct smbd_smb2_request
*req
;
205 uint32_t protocol_version
;
206 const uint8_t *inhdr
= NULL
;
209 uint32_t next_command_ofs
;
211 if (size
< (4 + SMB2_HDR_BODY
+ 2)) {
212 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size
));
213 return NT_STATUS_INVALID_PARAMETER
;
218 protocol_version
= IVAL(inhdr
, SMB2_HDR_PROTOCOL_ID
);
219 if (protocol_version
!= SMB2_MAGIC
) {
220 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
222 return NT_STATUS_INVALID_PARAMETER
;
225 cmd
= SVAL(inhdr
, SMB2_HDR_OPCODE
);
226 if (cmd
!= SMB2_OP_NEGPROT
) {
227 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
229 return NT_STATUS_INVALID_PARAMETER
;
232 next_command_ofs
= IVAL(inhdr
, SMB2_HDR_NEXT_COMMAND
);
233 if (next_command_ofs
!= 0) {
234 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
236 return NT_STATUS_INVALID_PARAMETER
;
239 req
= smbd_smb2_request_allocate(sconn
);
241 return NT_STATUS_NO_MEMORY
;
245 talloc_steal(req
, inbuf
);
247 req
->in
.vector
= talloc_array(req
, struct iovec
, 4);
248 if (req
->in
.vector
== NULL
) {
250 return NT_STATUS_NO_MEMORY
;
252 req
->in
.vector_count
= 4;
254 memcpy(req
->in
.nbt_hdr
, inbuf
, 4);
257 req
->in
.vector
[0].iov_base
= (void *)req
->in
.nbt_hdr
;
258 req
->in
.vector
[0].iov_len
= 4;
259 ofs
+= req
->in
.vector
[0].iov_len
;
261 req
->in
.vector
[1].iov_base
= (void *)(inbuf
+ ofs
);
262 req
->in
.vector
[1].iov_len
= SMB2_HDR_BODY
;
263 ofs
+= req
->in
.vector
[1].iov_len
;
265 req
->in
.vector
[2].iov_base
= (void *)(inbuf
+ ofs
);
266 req
->in
.vector
[2].iov_len
= SVAL(inbuf
, ofs
) & 0xFFFE;
267 ofs
+= req
->in
.vector
[2].iov_len
;
270 return NT_STATUS_INVALID_PARAMETER
;
273 req
->in
.vector
[3].iov_base
= (void *)(inbuf
+ ofs
);
274 req
->in
.vector
[3].iov_len
= size
- ofs
;
275 ofs
+= req
->in
.vector
[3].iov_len
;
277 req
->current_idx
= 1;
283 static NTSTATUS
smbd_smb2_request_validate(struct smbd_smb2_request
*req
,
284 uint16_t *p_creds_requested
)
288 bool compound_related
= false;
290 *p_creds_requested
= 0;
291 count
= req
->in
.vector_count
;
294 /* It's not a SMB2 request */
295 return NT_STATUS_INVALID_PARAMETER
;
298 for (idx
=1; idx
< count
; idx
+= 3) {
299 uint16_t creds_requested
= 0;
300 const uint8_t *inhdr
= NULL
;
303 if (req
->in
.vector
[idx
].iov_len
!= SMB2_HDR_BODY
) {
304 return NT_STATUS_INVALID_PARAMETER
;
307 if (req
->in
.vector
[idx
+1].iov_len
< 2) {
308 return NT_STATUS_INVALID_PARAMETER
;
311 inhdr
= (const uint8_t *)req
->in
.vector
[idx
].iov_base
;
313 /* setup the SMB2 header */
314 if (IVAL(inhdr
, SMB2_HDR_PROTOCOL_ID
) != SMB2_MAGIC
) {
315 return NT_STATUS_INVALID_PARAMETER
;
318 creds_requested
= SVAL(inhdr
, SMB2_HDR_CREDIT
);
319 if (*p_creds_requested
+ creds_requested
< creds_requested
) {
320 *p_creds_requested
= 65535;
322 *p_creds_requested
+= creds_requested
;
325 flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
328 * the 1st request should never have the
329 * SMB2_HDR_FLAG_CHAINED flag set
331 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
332 req
->next_status
= NT_STATUS_INVALID_PARAMETER
;
335 } else if (idx
== 4) {
337 * the 2nd request triggers related vs. unrelated
338 * compounded requests
340 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
341 compound_related
= true;
343 } else if (idx
> 4) {
346 * It seems the this tests are wrong
347 * see the SMB2-COMPOUND test
351 * all other requests should match the 2nd one
353 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
354 if (!compound_related
) {
356 NT_STATUS_INVALID_PARAMETER
;
360 if (compound_related
) {
362 NT_STATUS_INVALID_PARAMETER
;
373 static NTSTATUS
smbd_smb2_request_setup_out(struct smbd_smb2_request
*req
, uint16_t creds
)
375 struct iovec
*vector
;
379 count
= req
->in
.vector_count
;
380 vector
= talloc_array(req
, struct iovec
, count
);
381 if (vector
== NULL
) {
382 return NT_STATUS_NO_MEMORY
;
385 vector
[0].iov_base
= req
->out
.nbt_hdr
;
386 vector
[0].iov_len
= 4;
387 SIVAL(req
->out
.nbt_hdr
, 0, 0);
389 for (idx
=1; idx
< count
; idx
+= 3) {
390 const uint8_t *inhdr
= NULL
;
392 uint8_t *outhdr
= NULL
;
393 uint8_t *outbody
= NULL
;
394 uint32_t next_command_ofs
= 0;
395 struct iovec
*current
= &vector
[idx
];
397 if ((idx
+ 3) < count
) {
398 /* we have a next command */
399 next_command_ofs
= SMB2_HDR_BODY
+ 8;
402 inhdr
= (const uint8_t *)req
->in
.vector
[idx
].iov_base
;
403 in_flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
405 outhdr
= talloc_array(vector
, uint8_t,
407 if (outhdr
== NULL
) {
408 return NT_STATUS_NO_MEMORY
;
411 outbody
= outhdr
+ SMB2_HDR_BODY
;
413 current
[0].iov_base
= (void *)outhdr
;
414 current
[0].iov_len
= SMB2_HDR_BODY
;
416 current
[1].iov_base
= (void *)outbody
;
417 current
[1].iov_len
= 8;
419 current
[2].iov_base
= NULL
;
420 current
[2].iov_len
= 0;
422 /* setup the SMB2 header */
423 SIVAL(outhdr
, SMB2_HDR_PROTOCOL_ID
, SMB2_MAGIC
);
424 SSVAL(outhdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
425 SSVAL(outhdr
, SMB2_HDR_EPOCH
, 0);
426 SIVAL(outhdr
, SMB2_HDR_STATUS
,
427 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR
));
428 SSVAL(outhdr
, SMB2_HDR_OPCODE
,
429 SVAL(inhdr
, SMB2_HDR_OPCODE
));
430 SSVAL(outhdr
, SMB2_HDR_CREDIT
, creds
);
431 SIVAL(outhdr
, SMB2_HDR_FLAGS
,
432 IVAL(inhdr
, SMB2_HDR_FLAGS
) | SMB2_HDR_FLAG_REDIRECT
);
433 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, next_command_ofs
);
434 SBVAL(outhdr
, SMB2_HDR_MESSAGE_ID
,
435 BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
));
436 SIVAL(outhdr
, SMB2_HDR_PID
,
437 IVAL(inhdr
, SMB2_HDR_PID
));
438 SIVAL(outhdr
, SMB2_HDR_TID
,
439 IVAL(inhdr
, SMB2_HDR_TID
));
440 SBVAL(outhdr
, SMB2_HDR_SESSION_ID
,
441 BVAL(inhdr
, SMB2_HDR_SESSION_ID
));
442 memset(outhdr
+ SMB2_HDR_SIGNATURE
, 0, 16);
444 /* setup error body header */
445 SSVAL(outbody
, 0x00, 0x08 + 1);
446 SSVAL(outbody
, 0x02, 0);
447 SIVAL(outbody
, 0x04, 0);
450 req
->out
.vector
= vector
;
451 req
->out
.vector_count
= count
;
453 /* setup the length of the NBT packet */
454 smb2_setup_nbt_length(req
->out
.vector
, req
->out
.vector_count
);
456 DLIST_ADD_END(req
->sconn
->smb2
.requests
, req
, struct smbd_smb2_request
*);
461 void smbd_server_connection_terminate_ex(struct smbd_server_connection
*sconn
,
463 const char *location
)
465 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
467 exit_server_cleanly(reason
);
470 static bool dup_smb2_vec(struct iovec
*dstvec
,
471 const struct iovec
*srcvec
,
475 if (srcvec
[offset
].iov_len
&&
476 srcvec
[offset
].iov_base
) {
477 dstvec
[offset
].iov_base
= talloc_memdup(dstvec
,
478 srcvec
[offset
].iov_base
,
479 srcvec
[offset
].iov_len
);
480 if (!dstvec
[offset
].iov_base
) {
483 dstvec
[offset
].iov_len
= srcvec
[offset
].iov_len
;
485 dstvec
[offset
].iov_base
= NULL
;
486 dstvec
[offset
].iov_len
= 0;
491 static struct smbd_smb2_request
*dup_smb2_req(const struct smbd_smb2_request
*req
)
493 struct smbd_smb2_request
*newreq
= NULL
;
494 struct iovec
*outvec
= NULL
;
495 int count
= req
->out
.vector_count
;
498 newreq
= smbd_smb2_request_allocate(req
->sconn
);
503 newreq
->sconn
= req
->sconn
;
504 newreq
->do_signing
= req
->do_signing
;
505 newreq
->current_idx
= req
->current_idx
;
506 newreq
->async
= false;
507 newreq
->cancelled
= false;
509 outvec
= talloc_array(newreq
, struct iovec
, count
);
514 newreq
->out
.vector
= outvec
;
515 newreq
->out
.vector_count
= count
;
517 /* Setup the outvec's identically to req. */
518 outvec
[0].iov_base
= newreq
->out
.nbt_hdr
;
519 outvec
[0].iov_len
= 4;
520 memcpy(newreq
->out
.nbt_hdr
, req
->out
.nbt_hdr
, 4);
522 for (i
= 1; i
< count
; i
++) {
523 if (!dup_smb2_vec(outvec
,
531 smb2_setup_nbt_length(newreq
->out
.vector
,
532 newreq
->out
.vector_count
);
537 static void smbd_smb2_request_writev_done(struct tevent_req
*subreq
);
539 static NTSTATUS
smb2_send_async_interim_response(const struct smbd_smb2_request
*req
)
542 uint8_t *outhdr
= NULL
;
543 struct smbd_smb2_request
*nreq
= NULL
;
545 /* Create a new smb2 request we'll use
546 for the interim return. */
547 nreq
= dup_smb2_req(req
);
549 return NT_STATUS_NO_MEMORY
;
552 /* Lose the last 3 out vectors. They're the
553 ones we'll be using for the async reply. */
554 nreq
->out
.vector_count
-= 3;
556 smb2_setup_nbt_length(nreq
->out
.vector
,
557 nreq
->out
.vector_count
);
559 /* Step back to the previous reply. */
560 i
= nreq
->current_idx
- 3;
561 outhdr
= nreq
->out
.vector
[i
].iov_base
;
562 /* And end the chain. */
563 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, 0);
565 /* Re-sign if needed. */
566 if (nreq
->do_signing
) {
568 status
= smb2_signing_sign_pdu(nreq
->session
->session_key
,
569 &nreq
->out
.vector
[i
], 3);
570 if (!NT_STATUS_IS_OK(status
)) {
574 if (DEBUGLEVEL
>= 10) {
575 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
576 (unsigned int)nreq
->current_idx
);
577 dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
578 (unsigned int)nreq
->out
.vector_count
);
579 print_req_vectors(nreq
);
581 nreq
->subreq
= tstream_writev_queue_send(nreq
,
582 nreq
->sconn
->smb2
.event_ctx
,
583 nreq
->sconn
->smb2
.stream
,
584 nreq
->sconn
->smb2
.send_queue
,
586 nreq
->out
.vector_count
);
588 if (nreq
->subreq
== NULL
) {
589 return NT_STATUS_NO_MEMORY
;
592 tevent_req_set_callback(nreq
->subreq
,
593 smbd_smb2_request_writev_done
,
599 struct smbd_smb2_request_pending_state
{
600 struct smbd_server_connection
*sconn
;
601 uint8_t buf
[4 + SMB2_HDR_BODY
+ 0x08 + 1];
602 struct iovec vector
[3];
605 static void smbd_smb2_request_pending_writev_done(struct tevent_req
*subreq
)
607 struct smbd_smb2_request_pending_state
*state
=
608 tevent_req_callback_data(subreq
,
609 struct smbd_smb2_request_pending_state
);
610 struct smbd_server_connection
*sconn
= state
->sconn
;
614 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
617 NTSTATUS status
= map_nt_error_from_unix(sys_errno
);
618 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
625 NTSTATUS
smbd_smb2_request_pending_queue(struct smbd_smb2_request
*req
,
626 struct tevent_req
*subreq
)
629 struct smbd_smb2_request_pending_state
*state
= NULL
;
630 int i
= req
->current_idx
;
631 uint8_t *reqhdr
= NULL
;
633 uint8_t *body
= NULL
;
635 uint64_t message_id
= 0;
636 uint64_t async_id
= 0;
637 struct iovec
*outvec
= NULL
;
639 if (!tevent_req_is_in_progress(subreq
)) {
644 /* We're already async. */
648 if (req
->in
.vector_count
> i
+ 3) {
650 * We're trying to go async in a compound
651 * request chain. This is not allowed.
652 * Cancel the outstanding request.
654 tevent_req_cancel(subreq
);
655 return smbd_smb2_request_error(req
,
656 NT_STATUS_INSUFFICIENT_RESOURCES
);
659 req
->subreq
= subreq
;
662 if (DEBUGLEVEL
>= 10) {
663 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
664 (unsigned int)req
->current_idx
);
665 print_req_vectors(req
);
668 if (req
->out
.vector_count
> 4) {
669 /* This is a compound reply. We
670 * must do an interim response
671 * followed by the async response
674 status
= smb2_send_async_interim_response(req
);
675 if (!NT_STATUS_IS_OK(status
)) {
680 reqhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
681 flags
= IVAL(reqhdr
, SMB2_HDR_FLAGS
);
682 message_id
= BVAL(reqhdr
, SMB2_HDR_MESSAGE_ID
);
683 async_id
= message_id
; /* keep it simple for now... */
686 * What we send is identical to a smbd_smb2_request_error
687 * packet with an error status of STATUS_PENDING. Make use
688 * of this fact sometime when refactoring. JRA.
691 state
= talloc_zero(req
->sconn
, struct smbd_smb2_request_pending_state
);
693 return NT_STATUS_NO_MEMORY
;
695 state
->sconn
= req
->sconn
;
697 state
->vector
[0].iov_base
= (void *)state
->buf
;
698 state
->vector
[0].iov_len
= 4;
700 state
->vector
[1].iov_base
= state
->buf
+ 4;
701 state
->vector
[1].iov_len
= SMB2_HDR_BODY
;
703 state
->vector
[2].iov_base
= state
->buf
+ 4 + SMB2_HDR_BODY
;
704 state
->vector
[2].iov_len
= 9;
706 smb2_setup_nbt_length(state
->vector
, 3);
708 hdr
= state
->vector
[1].iov_base
;
709 body
= state
->vector
[2].iov_base
;
711 SIVAL(hdr
, SMB2_HDR_PROTOCOL_ID
, SMB2_MAGIC
);
712 SSVAL(hdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
713 SSVAL(hdr
, SMB2_HDR_EPOCH
, 0);
714 SIVAL(hdr
, SMB2_HDR_STATUS
, NT_STATUS_V(STATUS_PENDING
));
715 SSVAL(hdr
, SMB2_HDR_OPCODE
, SVAL(reqhdr
, SMB2_HDR_OPCODE
));
716 SSVAL(hdr
, SMB2_HDR_CREDIT
, 5);
717 SIVAL(hdr
, SMB2_HDR_FLAGS
, flags
| SMB2_HDR_FLAG_ASYNC
);
718 SIVAL(hdr
, SMB2_HDR_NEXT_COMMAND
, 0);
719 SBVAL(hdr
, SMB2_HDR_MESSAGE_ID
, message_id
);
720 SBVAL(hdr
, SMB2_HDR_PID
, async_id
);
721 SBVAL(hdr
, SMB2_HDR_SESSION_ID
,
722 BVAL(reqhdr
, SMB2_HDR_SESSION_ID
));
723 memset(hdr
+SMB2_HDR_SIGNATURE
, 0, 16);
725 SSVAL(body
, 0x00, 0x08 + 1);
727 SCVAL(body
, 0x02, 0);
728 SCVAL(body
, 0x03, 0);
729 SIVAL(body
, 0x04, 0);
730 /* Match W2K8R2... */
731 SCVAL(body
, 0x08, 0x21);
733 if (req
->do_signing
) {
734 status
= smb2_signing_sign_pdu(req
->session
->session_key
,
736 if (!NT_STATUS_IS_OK(status
)) {
741 subreq
= tstream_writev_queue_send(state
,
742 req
->sconn
->smb2
.event_ctx
,
743 req
->sconn
->smb2
.stream
,
744 req
->sconn
->smb2
.send_queue
,
748 if (subreq
== NULL
) {
749 return NT_STATUS_NO_MEMORY
;
752 tevent_req_set_callback(subreq
,
753 smbd_smb2_request_pending_writev_done
,
756 /* Note we're going async with this request. */
760 * Now manipulate req so that the outstanding async request
761 * is the only one left in the struct smbd_smb2_request.
764 if (req
->current_idx
== 1) {
765 /* There was only one. */
769 /* Re-arrange the in.vectors. */
770 req
->in
.vector
[1] = req
->in
.vector
[i
];
771 req
->in
.vector
[2] = req
->in
.vector
[i
+1];
772 req
->in
.vector
[3] = req
->in
.vector
[i
+2];
773 req
->in
.vector_count
= 4;
774 /* Reset the new in size. */
775 smb2_setup_nbt_length(req
->in
.vector
, 4);
777 /* Now recreate the out.vectors. */
778 outvec
= talloc_array(req
, struct iovec
, 4);
780 return NT_STATUS_NO_MEMORY
;
782 outvec
[0].iov_base
= req
->out
.nbt_hdr
;
783 outvec
[0].iov_len
= 4;
784 SIVAL(req
->out
.nbt_hdr
, 0, 0);
786 outvec
[1].iov_base
= talloc_memdup(outvec
,
787 req
->out
.vector
[i
].iov_base
,
789 if (!outvec
[1].iov_base
) {
790 return NT_STATUS_NO_MEMORY
;
792 outvec
[1].iov_len
= SMB2_HDR_BODY
;
794 outvec
[2].iov_base
= ((uint8_t *)outvec
[1].iov_base
) +
796 outvec
[2].iov_len
= 8;
798 if (req
->out
.vector
[i
+2].iov_base
&&
799 req
->out
.vector
[i
+2].iov_len
) {
800 outvec
[3].iov_base
= talloc_memdup(outvec
,
801 req
->out
.vector
[i
+2].iov_base
,
802 req
->out
.vector
[i
+2].iov_len
);
803 if (!outvec
[3].iov_base
) {
804 return NT_STATUS_NO_MEMORY
;
806 outvec
[3].iov_len
= req
->out
.vector
[i
+2].iov_len
;
808 outvec
[3].iov_base
= NULL
;
809 outvec
[3].iov_len
= 0;
812 TALLOC_FREE(req
->out
.vector
);
814 req
->out
.vector
= outvec
;
816 req
->current_idx
= 1;
817 req
->out
.vector_count
= 4;
821 smb2_setup_nbt_length(req
->out
.vector
,
822 req
->out
.vector_count
);
824 /* Ensure our final reply matches the interim one. */
825 reqhdr
= (uint8_t *)req
->out
.vector
[1].iov_base
;
826 SIVAL(reqhdr
, SMB2_HDR_FLAGS
, flags
| SMB2_HDR_FLAG_ASYNC
);
827 SBVAL(reqhdr
, SMB2_HDR_PID
, async_id
);
830 const uint8_t *inhdr
=
831 (const uint8_t *)req
->in
.vector
[1].iov_base
;
832 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
834 smb2_opcode_name((uint16_t)IVAL(inhdr
, SMB2_HDR_OPCODE
)),
835 (unsigned long long)async_id
));
840 static NTSTATUS
smbd_smb2_request_process_cancel(struct smbd_smb2_request
*req
)
842 struct smbd_server_connection
*sconn
= req
->sconn
;
843 struct smbd_smb2_request
*cur
;
844 const uint8_t *inhdr
;
845 int i
= req
->current_idx
;
847 uint64_t search_message_id
;
848 uint64_t search_async_id
;
851 inhdr
= (const uint8_t *)req
->in
.vector
[i
].iov_base
;
853 flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
854 search_message_id
= BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
);
855 search_async_id
= BVAL(inhdr
, SMB2_HDR_PID
);
858 * we don't need the request anymore
859 * cancel requests never have a response
863 for (cur
= sconn
->smb2
.requests
; cur
; cur
= cur
->next
) {
864 const uint8_t *outhdr
;
868 i
= cur
->current_idx
;
870 outhdr
= (const uint8_t *)cur
->out
.vector
[i
].iov_base
;
872 message_id
= BVAL(outhdr
, SMB2_HDR_MESSAGE_ID
);
873 async_id
= BVAL(outhdr
, SMB2_HDR_PID
);
875 if (flags
& SMB2_HDR_FLAG_ASYNC
) {
876 if (search_async_id
== async_id
) {
881 if (search_message_id
== message_id
) {
882 found_id
= message_id
;
888 if (cur
&& cur
->subreq
) {
889 inhdr
= (const uint8_t *)cur
->in
.vector
[i
].iov_base
;
890 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
891 "cancel opcode[%s] mid %llu\n",
892 smb2_opcode_name((uint16_t)IVAL(inhdr
, SMB2_HDR_OPCODE
)),
893 (unsigned long long)found_id
));
894 tevent_req_cancel(cur
->subreq
);
900 static NTSTATUS
smbd_smb2_request_dispatch(struct smbd_smb2_request
*req
)
902 const uint8_t *inhdr
;
903 int i
= req
->current_idx
;
908 NTSTATUS session_status
;
909 uint32_t allowed_flags
;
911 inhdr
= (const uint8_t *)req
->in
.vector
[i
].iov_base
;
913 /* TODO: verify more things */
915 flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
916 opcode
= IVAL(inhdr
, SMB2_HDR_OPCODE
);
917 mid
= BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
);
918 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
919 smb2_opcode_name(opcode
),
920 (unsigned long long)mid
));
922 allowed_flags
= SMB2_HDR_FLAG_CHAINED
|
923 SMB2_HDR_FLAG_SIGNED
|
925 if (opcode
== SMB2_OP_CANCEL
) {
926 allowed_flags
|= SMB2_HDR_FLAG_ASYNC
;
928 if ((flags
& ~allowed_flags
) != 0) {
929 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
932 session_status
= smbd_smb2_request_check_session(req
);
934 req
->do_signing
= false;
935 if (flags
& SMB2_HDR_FLAG_SIGNED
) {
936 if (!NT_STATUS_IS_OK(session_status
)) {
937 return smbd_smb2_request_error(req
, session_status
);
940 req
->do_signing
= true;
941 status
= smb2_signing_check_pdu(req
->session
->session_key
,
942 &req
->in
.vector
[i
], 3);
943 if (!NT_STATUS_IS_OK(status
)) {
944 return smbd_smb2_request_error(req
, status
);
946 } else if (req
->session
&& req
->session
->do_signing
) {
947 return smbd_smb2_request_error(req
, NT_STATUS_ACCESS_DENIED
);
950 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
952 * This check is mostly for giving the correct error code
953 * for compounded requests.
955 * TODO: we may need to move this after the session
958 if (!NT_STATUS_IS_OK(req
->next_status
)) {
959 return smbd_smb2_request_error(req
, req
->next_status
);
962 req
->compat_chain_fsp
= NULL
;
966 case SMB2_OP_NEGPROT
:
967 return smbd_smb2_request_process_negprot(req
);
969 case SMB2_OP_SESSSETUP
:
970 return smbd_smb2_request_process_sesssetup(req
);
973 if (!NT_STATUS_IS_OK(session_status
)) {
974 return smbd_smb2_request_error(req
, session_status
);
976 return smbd_smb2_request_process_logoff(req
);
979 if (!NT_STATUS_IS_OK(session_status
)) {
980 return smbd_smb2_request_error(req
, session_status
);
982 status
= smbd_smb2_request_check_session(req
);
983 if (!NT_STATUS_IS_OK(status
)) {
984 return smbd_smb2_request_error(req
, status
);
986 return smbd_smb2_request_process_tcon(req
);
989 if (!NT_STATUS_IS_OK(session_status
)) {
990 return smbd_smb2_request_error(req
, session_status
);
992 status
= smbd_smb2_request_check_tcon(req
);
993 if (!NT_STATUS_IS_OK(status
)) {
994 return smbd_smb2_request_error(req
, status
);
996 return smbd_smb2_request_process_tdis(req
);
999 if (!NT_STATUS_IS_OK(session_status
)) {
1000 return smbd_smb2_request_error(req
, session_status
);
1002 status
= smbd_smb2_request_check_tcon(req
);
1003 if (!NT_STATUS_IS_OK(status
)) {
1004 return smbd_smb2_request_error(req
, status
);
1006 return smbd_smb2_request_process_create(req
);
1009 if (!NT_STATUS_IS_OK(session_status
)) {
1010 return smbd_smb2_request_error(req
, session_status
);
1012 status
= smbd_smb2_request_check_tcon(req
);
1013 if (!NT_STATUS_IS_OK(status
)) {
1014 return smbd_smb2_request_error(req
, status
);
1016 return smbd_smb2_request_process_close(req
);
1019 if (!NT_STATUS_IS_OK(session_status
)) {
1020 return smbd_smb2_request_error(req
, session_status
);
1022 status
= smbd_smb2_request_check_tcon(req
);
1023 if (!NT_STATUS_IS_OK(status
)) {
1024 return smbd_smb2_request_error(req
, status
);
1026 return smbd_smb2_request_process_flush(req
);
1029 if (!NT_STATUS_IS_OK(session_status
)) {
1030 return smbd_smb2_request_error(req
, session_status
);
1032 status
= smbd_smb2_request_check_tcon(req
);
1033 if (!NT_STATUS_IS_OK(status
)) {
1034 return smbd_smb2_request_error(req
, status
);
1036 return smbd_smb2_request_process_read(req
);
1039 if (!NT_STATUS_IS_OK(session_status
)) {
1040 return smbd_smb2_request_error(req
, session_status
);
1042 status
= smbd_smb2_request_check_tcon(req
);
1043 if (!NT_STATUS_IS_OK(status
)) {
1044 return smbd_smb2_request_error(req
, status
);
1046 return smbd_smb2_request_process_write(req
);
1049 if (!NT_STATUS_IS_OK(session_status
)) {
1050 return smbd_smb2_request_error(req
, session_status
);
1052 status
= smbd_smb2_request_check_tcon(req
);
1053 if (!NT_STATUS_IS_OK(status
)) {
1054 return smbd_smb2_request_error(req
, status
);
1056 return smbd_smb2_request_process_lock(req
);
1059 if (!NT_STATUS_IS_OK(session_status
)) {
1060 return smbd_smb2_request_error(req
, session_status
);
1062 status
= smbd_smb2_request_check_tcon(req
);
1063 if (!NT_STATUS_IS_OK(status
)) {
1064 return smbd_smb2_request_error(req
, status
);
1066 return smbd_smb2_request_process_ioctl(req
);
1068 case SMB2_OP_CANCEL
:
1069 return smbd_smb2_request_process_cancel(req
);
1071 case SMB2_OP_KEEPALIVE
:
1072 return smbd_smb2_request_process_keepalive(req
);
1075 if (!NT_STATUS_IS_OK(session_status
)) {
1076 return smbd_smb2_request_error(req
, session_status
);
1078 status
= smbd_smb2_request_check_tcon(req
);
1079 if (!NT_STATUS_IS_OK(status
)) {
1080 return smbd_smb2_request_error(req
, status
);
1082 return smbd_smb2_request_process_find(req
);
1084 case SMB2_OP_NOTIFY
:
1085 if (!NT_STATUS_IS_OK(session_status
)) {
1086 return smbd_smb2_request_error(req
, session_status
);
1088 status
= smbd_smb2_request_check_tcon(req
);
1089 if (!NT_STATUS_IS_OK(status
)) {
1090 return smbd_smb2_request_error(req
, status
);
1092 return smbd_smb2_request_process_notify(req
);
1094 case SMB2_OP_GETINFO
:
1095 if (!NT_STATUS_IS_OK(session_status
)) {
1096 return smbd_smb2_request_error(req
, session_status
);
1098 status
= smbd_smb2_request_check_tcon(req
);
1099 if (!NT_STATUS_IS_OK(status
)) {
1100 return smbd_smb2_request_error(req
, status
);
1102 return smbd_smb2_request_process_getinfo(req
);
1104 case SMB2_OP_SETINFO
:
1105 if (!NT_STATUS_IS_OK(session_status
)) {
1106 return smbd_smb2_request_error(req
, session_status
);
1108 status
= smbd_smb2_request_check_tcon(req
);
1109 if (!NT_STATUS_IS_OK(status
)) {
1110 return smbd_smb2_request_error(req
, status
);
1112 return smbd_smb2_request_process_setinfo(req
);
1115 if (!NT_STATUS_IS_OK(session_status
)) {
1116 return smbd_smb2_request_error(req
, session_status
);
1118 status
= smbd_smb2_request_check_tcon(req
);
1119 if (!NT_STATUS_IS_OK(status
)) {
1120 return smbd_smb2_request_error(req
, status
);
1122 return smbd_smb2_request_process_break(req
);
1125 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
1128 static void smbd_smb2_request_dispatch_compound(struct tevent_context
*ctx
,
1129 struct tevent_immediate
*im
,
1130 void *private_data
);
1132 static NTSTATUS
smbd_smb2_request_reply(struct smbd_smb2_request
*req
)
1134 struct tevent_req
*subreq
;
1138 smb2_setup_nbt_length(req
->out
.vector
, req
->out
.vector_count
);
1140 if (req
->do_signing
) {
1141 int i
= req
->current_idx
;
1143 status
= smb2_signing_sign_pdu(req
->session
->session_key
,
1144 &req
->out
.vector
[i
], 3);
1145 if (!NT_STATUS_IS_OK(status
)) {
1150 req
->current_idx
+= 3;
1152 if (req
->current_idx
< req
->out
.vector_count
) {
1154 * We must process the remaining compound
1155 * SMB2 requests before any new incoming SMB2
1156 * requests. This is because incoming SMB2
1157 * requests may include a cancel for a
1158 * compound request we haven't processed
1161 struct tevent_immediate
*im
= tevent_create_immediate(req
);
1163 return NT_STATUS_NO_MEMORY
;
1165 tevent_schedule_immediate(im
,
1166 req
->sconn
->smb2
.event_ctx
,
1167 smbd_smb2_request_dispatch_compound
,
1169 return NT_STATUS_OK
;
1172 if (DEBUGLEVEL
>= 10) {
1173 dbgtext("smbd_smb2_request_reply: sending...\n");
1174 print_req_vectors(req
);
1177 subreq
= tstream_writev_queue_send(req
,
1178 req
->sconn
->smb2
.event_ctx
,
1179 req
->sconn
->smb2
.stream
,
1180 req
->sconn
->smb2
.send_queue
,
1182 req
->out
.vector_count
);
1183 if (subreq
== NULL
) {
1184 return NT_STATUS_NO_MEMORY
;
1186 tevent_req_set_callback(subreq
, smbd_smb2_request_writev_done
, req
);
1188 return NT_STATUS_OK
;
1191 static void smbd_smb2_request_dispatch_compound(struct tevent_context
*ctx
,
1192 struct tevent_immediate
*im
,
1195 struct smbd_smb2_request
*req
= talloc_get_type_abort(private_data
,
1196 struct smbd_smb2_request
);
1197 struct smbd_server_connection
*sconn
= req
->sconn
;
1202 if (DEBUGLEVEL
>= 10) {
1203 DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n",
1204 req
->current_idx
, req
->in
.vector_count
));
1205 print_req_vectors(req
);
1208 status
= smbd_smb2_request_dispatch(req
);
1209 if (!NT_STATUS_IS_OK(status
)) {
1210 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1215 static void smbd_smb2_request_writev_done(struct tevent_req
*subreq
)
1217 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
1218 struct smbd_smb2_request
);
1219 struct smbd_server_connection
*sconn
= req
->sconn
;
1223 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
1224 TALLOC_FREE(subreq
);
1227 NTSTATUS status
= map_nt_error_from_unix(sys_errno
);
1228 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
1229 nt_errstr(status
)));
1230 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1235 NTSTATUS
smbd_smb2_request_error_ex(struct smbd_smb2_request
*req
,
1238 const char *location
)
1242 int i
= req
->current_idx
;
1244 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
1245 i
, nt_errstr(status
), info
? " +info" : "",
1248 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
1250 SIVAL(outhdr
, SMB2_HDR_STATUS
, NT_STATUS_V(status
));
1252 outbody
= outhdr
+ SMB2_HDR_BODY
;
1253 SSVAL(outbody
, 0, 9);
1255 req
->out
.vector
[i
+1].iov_base
= (void *)outbody
;
1256 req
->out
.vector
[i
+1].iov_len
= 8;
1259 SIVAL(outbody
, 0x04, info
->length
);
1260 req
->out
.vector
[i
+2].iov_base
= (void *)info
->data
;
1261 req
->out
.vector
[i
+2].iov_len
= info
->length
;
1263 req
->out
.vector
[i
+2].iov_base
= talloc_array(req
, uint8_t, 1);
1264 if (!req
->out
.vector
[i
+2].iov_base
) {
1265 return NT_STATUS_NO_MEMORY
;
1267 SCVAL(req
->out
.vector
[i
+2].iov_base
, 0, 0);
1268 req
->out
.vector
[i
+2].iov_len
= 1;
1272 * if a request fails, all other remaining
1273 * compounded requests should fail too
1275 req
->next_status
= NT_STATUS_INVALID_PARAMETER
;
1277 return smbd_smb2_request_reply(req
);
1280 NTSTATUS
smbd_smb2_request_done_ex(struct smbd_smb2_request
*req
,
1282 DATA_BLOB body
, DATA_BLOB
*dyn
,
1283 const char *location
)
1287 int i
= req
->current_idx
;
1288 uint32_t next_command_ofs
;
1290 DEBUG(10,("smbd_smb2_request_done_ex: "
1291 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
1292 i
, nt_errstr(status
), (unsigned int)body
.length
,
1294 (unsigned int)(dyn
? dyn
->length
: 0),
1297 if (body
.length
< 2) {
1298 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
1301 if ((body
.length
% 2) != 0) {
1302 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
1305 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
1306 /* the fallback dynamic buffer */
1307 outdyn
= outhdr
+ SMB2_HDR_BODY
+ 8;
1309 next_command_ofs
= IVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
);
1310 SIVAL(outhdr
, SMB2_HDR_STATUS
, NT_STATUS_V(status
));
1312 req
->out
.vector
[i
+1].iov_base
= (void *)body
.data
;
1313 req
->out
.vector
[i
+1].iov_len
= body
.length
;
1316 req
->out
.vector
[i
+2].iov_base
= (void *)dyn
->data
;
1317 req
->out
.vector
[i
+2].iov_len
= dyn
->length
;
1319 req
->out
.vector
[i
+2].iov_base
= NULL
;
1320 req
->out
.vector
[i
+2].iov_len
= 0;
1323 /* see if we need to recalculate the offset to the next response */
1324 if (next_command_ofs
> 0) {
1325 next_command_ofs
= SMB2_HDR_BODY
;
1326 next_command_ofs
+= req
->out
.vector
[i
+1].iov_len
;
1327 next_command_ofs
+= req
->out
.vector
[i
+2].iov_len
;
1330 if ((next_command_ofs
% 8) != 0) {
1331 size_t pad_size
= 8 - (next_command_ofs
% 8);
1332 if (req
->out
.vector
[i
+2].iov_len
== 0) {
1334 * if the dyn buffer is empty
1335 * we can use it to add padding
1339 pad
= talloc_zero_array(req
->out
.vector
,
1342 return smbd_smb2_request_error(req
,
1343 NT_STATUS_NO_MEMORY
);
1346 req
->out
.vector
[i
+2].iov_base
= (void *)pad
;
1347 req
->out
.vector
[i
+2].iov_len
= pad_size
;
1350 * For now we copy the dynamic buffer
1351 * and add the padding to the new buffer
1358 old_size
= req
->out
.vector
[i
+2].iov_len
;
1359 old_dyn
= (uint8_t *)req
->out
.vector
[i
+2].iov_base
;
1361 new_size
= old_size
+ pad_size
;
1362 new_dyn
= talloc_array(req
->out
.vector
,
1364 if (new_dyn
== NULL
) {
1365 return smbd_smb2_request_error(req
,
1366 NT_STATUS_NO_MEMORY
);
1369 memcpy(new_dyn
, old_dyn
, old_size
);
1370 memset(new_dyn
+ old_size
, 0, pad_size
);
1372 req
->out
.vector
[i
+2].iov_base
= (void *)new_dyn
;
1373 req
->out
.vector
[i
+2].iov_len
= new_size
;
1375 TALLOC_FREE(old_dyn
);
1377 next_command_ofs
+= pad_size
;
1380 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, next_command_ofs
);
1382 return smbd_smb2_request_reply(req
);
1385 struct smbd_smb2_send_oplock_break_state
{
1386 struct smbd_server_connection
*sconn
;
1387 uint8_t buf
[4 + SMB2_HDR_BODY
+ 0x18];
1388 struct iovec vector
;
1391 static void smbd_smb2_oplock_break_writev_done(struct tevent_req
*subreq
);
1393 NTSTATUS
smbd_smb2_send_oplock_break(struct smbd_server_connection
*sconn
,
1394 uint64_t file_id_persistent
,
1395 uint64_t file_id_volatile
,
1396 uint8_t oplock_level
)
1398 struct smbd_smb2_send_oplock_break_state
*state
;
1399 struct tevent_req
*subreq
;
1403 state
= talloc(sconn
, struct smbd_smb2_send_oplock_break_state
);
1404 if (state
== NULL
) {
1405 return NT_STATUS_NO_MEMORY
;
1407 state
->sconn
= sconn
;
1409 state
->vector
.iov_base
= (void *)state
->buf
;
1410 state
->vector
.iov_len
= sizeof(state
->buf
);
1412 _smb2_setlen(state
->buf
, sizeof(state
->buf
) - 4);
1413 hdr
= state
->buf
+ 4;
1414 body
= hdr
+ SMB2_HDR_BODY
;
1416 SIVAL(hdr
, 0, SMB2_MAGIC
);
1417 SSVAL(hdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
1418 SSVAL(hdr
, SMB2_HDR_EPOCH
, 0);
1419 SIVAL(hdr
, SMB2_HDR_STATUS
, 0);
1420 SSVAL(hdr
, SMB2_HDR_OPCODE
, SMB2_OP_BREAK
);
1421 SSVAL(hdr
, SMB2_HDR_CREDIT
, 0);
1422 SIVAL(hdr
, SMB2_HDR_FLAGS
, SMB2_HDR_FLAG_REDIRECT
);
1423 SIVAL(hdr
, SMB2_HDR_NEXT_COMMAND
, 0);
1424 SBVAL(hdr
, SMB2_HDR_MESSAGE_ID
, UINT64_MAX
);
1425 SIVAL(hdr
, SMB2_HDR_PID
, 0);
1426 SIVAL(hdr
, SMB2_HDR_TID
, 0);
1427 SBVAL(hdr
, SMB2_HDR_SESSION_ID
, 0);
1428 memset(hdr
+SMB2_HDR_SIGNATURE
, 0, 16);
1430 SSVAL(body
, 0x00, 0x18);
1432 SCVAL(body
, 0x02, oplock_level
);
1433 SCVAL(body
, 0x03, 0); /* reserved */
1434 SIVAL(body
, 0x04, 0); /* reserved */
1435 SBVAL(body
, 0x08, file_id_persistent
);
1436 SBVAL(body
, 0x10, file_id_volatile
);
1438 subreq
= tstream_writev_queue_send(state
,
1439 sconn
->smb2
.event_ctx
,
1441 sconn
->smb2
.send_queue
,
1443 if (subreq
== NULL
) {
1444 return NT_STATUS_NO_MEMORY
;
1446 tevent_req_set_callback(subreq
,
1447 smbd_smb2_oplock_break_writev_done
,
1450 return NT_STATUS_OK
;
1453 static void smbd_smb2_oplock_break_writev_done(struct tevent_req
*subreq
)
1455 struct smbd_smb2_send_oplock_break_state
*state
=
1456 tevent_req_callback_data(subreq
,
1457 struct smbd_smb2_send_oplock_break_state
);
1458 struct smbd_server_connection
*sconn
= state
->sconn
;
1462 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
1463 TALLOC_FREE(subreq
);
1465 NTSTATUS status
= map_nt_error_from_unix(sys_errno
);
1466 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1473 struct smbd_smb2_request_read_state
{
1475 bool asked_for_header
;
1476 struct smbd_smb2_request
*smb2_req
;
1479 static int smbd_smb2_request_next_vector(struct tstream_context
*stream
,
1481 TALLOC_CTX
*mem_ctx
,
1482 struct iovec
**_vector
,
1484 static void smbd_smb2_request_read_done(struct tevent_req
*subreq
);
1486 static struct tevent_req
*smbd_smb2_request_read_send(TALLOC_CTX
*mem_ctx
,
1487 struct tevent_context
*ev
,
1488 struct smbd_server_connection
*sconn
)
1490 struct tevent_req
*req
;
1491 struct smbd_smb2_request_read_state
*state
;
1492 struct tevent_req
*subreq
;
1494 req
= tevent_req_create(mem_ctx
, &state
,
1495 struct smbd_smb2_request_read_state
);
1500 state
->asked_for_header
= false;
1502 state
->smb2_req
= smbd_smb2_request_allocate(state
);
1503 if (tevent_req_nomem(state
->smb2_req
, req
)) {
1504 return tevent_req_post(req
, ev
);
1506 state
->smb2_req
->sconn
= sconn
;
1508 subreq
= tstream_readv_pdu_queue_send(state
, ev
, sconn
->smb2
.stream
,
1509 sconn
->smb2
.recv_queue
,
1510 smbd_smb2_request_next_vector
,
1512 if (tevent_req_nomem(subreq
, req
)) {
1513 return tevent_req_post(req
, ev
);
1515 tevent_req_set_callback(subreq
, smbd_smb2_request_read_done
, req
);
1520 static int smbd_smb2_request_next_vector(struct tstream_context
*stream
,
1522 TALLOC_CTX
*mem_ctx
,
1523 struct iovec
**_vector
,
1526 struct smbd_smb2_request_read_state
*state
=
1527 talloc_get_type_abort(private_data
,
1528 struct smbd_smb2_request_read_state
);
1529 struct smbd_smb2_request
*req
= state
->smb2_req
;
1530 struct iovec
*vector
;
1531 int idx
= req
->in
.vector_count
;
1533 uint8_t *buf
= NULL
;
1535 if (req
->in
.vector_count
== 0) {
1537 * first we need to get the NBT header
1539 req
->in
.vector
= talloc_array(req
, struct iovec
,
1540 req
->in
.vector_count
+ 1);
1541 if (req
->in
.vector
== NULL
) {
1544 req
->in
.vector_count
+= 1;
1546 req
->in
.vector
[idx
].iov_base
= (void *)req
->in
.nbt_hdr
;
1547 req
->in
.vector
[idx
].iov_len
= 4;
1549 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
1550 if (vector
== NULL
) {
1554 vector
[0] = req
->in
.vector
[idx
];
1561 if (req
->in
.vector_count
== 1) {
1563 * Now we analyze the NBT header
1565 state
->missing
= smb2_len(req
->in
.vector
[0].iov_base
);
1567 if (state
->missing
== 0) {
1568 /* if there're no remaining bytes, we're done */
1574 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
1576 req
->in
.vector_count
+ 1);
1577 if (req
->in
.vector
== NULL
) {
1580 req
->in
.vector_count
+= 1;
1582 if (CVAL(req
->in
.vector
[0].iov_base
, 0) != 0) {
1584 * it's a special NBT message,
1585 * so get all remaining bytes
1587 len
= state
->missing
;
1588 } else if (state
->missing
< (SMB2_HDR_BODY
+ 2)) {
1590 * it's an invalid message, just read what we can get
1591 * and let the caller handle the error
1593 len
= state
->missing
;
1596 * We assume it's a SMB2 request,
1597 * and we first get the header and the
1598 * first 2 bytes (the struct size) of the body
1600 len
= SMB2_HDR_BODY
+ 2;
1602 state
->asked_for_header
= true;
1605 state
->missing
-= len
;
1607 buf
= talloc_array(req
->in
.vector
, uint8_t, len
);
1612 req
->in
.vector
[idx
].iov_base
= (void *)buf
;
1613 req
->in
.vector
[idx
].iov_len
= len
;
1615 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
1616 if (vector
== NULL
) {
1620 vector
[0] = req
->in
.vector
[idx
];
1627 if (state
->missing
== 0) {
1628 /* if there're no remaining bytes, we're done */
1634 if (state
->asked_for_header
) {
1637 size_t next_command_ofs
;
1642 bool invalid
= false;
1644 state
->asked_for_header
= false;
1647 * We got the SMB2 header and the first 2 bytes
1648 * of the body. We fix the size to just the header
1649 * and manually copy the 2 first bytes to the body section
1651 req
->in
.vector
[idx
-1].iov_len
= SMB2_HDR_BODY
;
1652 hdr
= (const uint8_t *)req
->in
.vector
[idx
-1].iov_base
;
1654 /* allocate vectors for body and dynamic areas */
1655 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
1657 req
->in
.vector_count
+ 2);
1658 if (req
->in
.vector
== NULL
) {
1661 req
->in
.vector_count
+= 2;
1663 full_size
= state
->missing
+ SMB2_HDR_BODY
+ 2;
1664 next_command_ofs
= IVAL(hdr
, SMB2_HDR_NEXT_COMMAND
);
1665 body_size
= SVAL(hdr
, SMB2_HDR_BODY
);
1667 if (next_command_ofs
!= 0) {
1668 if (next_command_ofs
< (SMB2_HDR_BODY
+ 2)) {
1670 * this is invalid, just return a zero
1671 * body and let the caller deal with the error
1674 } else if (next_command_ofs
> full_size
) {
1676 * this is invalid, just return a zero
1677 * body and let the caller deal with the error
1681 full_size
= next_command_ofs
;
1686 if (body_size
< 2) {
1688 * this is invalid, just return a zero
1689 * body and let the caller deal with the error
1694 if ((body_size
% 2) != 0) {
1698 if (body_size
> (full_size
- SMB2_HDR_BODY
)) {
1700 * this is invalid, just return a zero
1701 * body and let the caller deal with the error
1708 /* the caller should check this */
1712 dyn_size
= full_size
- (SMB2_HDR_BODY
+ body_size
);
1714 state
->missing
-= (body_size
- 2) + dyn_size
;
1716 body
= talloc_array(req
->in
.vector
, uint8_t, body_size
);
1721 dyn
= talloc_array(req
->in
.vector
, uint8_t, dyn_size
);
1726 req
->in
.vector
[idx
].iov_base
= (void *)body
;
1727 req
->in
.vector
[idx
].iov_len
= body_size
;
1728 req
->in
.vector
[idx
+1].iov_base
= (void *)dyn
;
1729 req
->in
.vector
[idx
+1].iov_len
= dyn_size
;
1731 vector
= talloc_array(mem_ctx
, struct iovec
, 2);
1732 if (vector
== NULL
) {
1737 * the first 2 bytes of the body were already fetched
1738 * together with the header
1740 memcpy(body
, hdr
+ SMB2_HDR_BODY
, 2);
1741 vector
[0].iov_base
= body
+ 2;
1742 vector
[0].iov_len
= body_size
- 2;
1744 vector
[1] = req
->in
.vector
[idx
+1];
1752 * when we endup here, we're looking for a new SMB2 request
1753 * next. And we ask for its header and the first 2 bytes of
1754 * the body (like we did for the first SMB2 request).
1757 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
1759 req
->in
.vector_count
+ 1);
1760 if (req
->in
.vector
== NULL
) {
1763 req
->in
.vector_count
+= 1;
1766 * We assume it's a SMB2 request,
1767 * and we first get the header and the
1768 * first 2 bytes (the struct size) of the body
1770 len
= SMB2_HDR_BODY
+ 2;
1772 if (len
> state
->missing
) {
1773 /* let the caller handle the error */
1774 len
= state
->missing
;
1777 state
->missing
-= len
;
1778 state
->asked_for_header
= true;
1780 buf
= talloc_array(req
->in
.vector
, uint8_t, len
);
1785 req
->in
.vector
[idx
].iov_base
= (void *)buf
;
1786 req
->in
.vector
[idx
].iov_len
= len
;
1788 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
1789 if (vector
== NULL
) {
1793 vector
[0] = req
->in
.vector
[idx
];
1800 static void smbd_smb2_request_read_done(struct tevent_req
*subreq
)
1802 struct tevent_req
*req
=
1803 tevent_req_callback_data(subreq
,
1809 ret
= tstream_readv_pdu_queue_recv(subreq
, &sys_errno
);
1811 status
= map_nt_error_from_unix(sys_errno
);
1812 tevent_req_nterror(req
, status
);
1816 tevent_req_done(req
);
1819 static NTSTATUS
smbd_smb2_request_read_recv(struct tevent_req
*req
,
1820 TALLOC_CTX
*mem_ctx
,
1821 struct smbd_smb2_request
**_smb2_req
)
1823 struct smbd_smb2_request_read_state
*state
=
1824 tevent_req_data(req
,
1825 struct smbd_smb2_request_read_state
);
1828 if (tevent_req_is_nterror(req
, &status
)) {
1829 tevent_req_received(req
);
1833 talloc_steal(mem_ctx
, state
->smb2_req
->mem_pool
);
1834 *_smb2_req
= state
->smb2_req
;
1835 tevent_req_received(req
);
1836 return NT_STATUS_OK
;
1839 static void smbd_smb2_request_incoming(struct tevent_req
*subreq
);
1841 void smbd_smb2_first_negprot(struct smbd_server_connection
*sconn
,
1842 const uint8_t *inbuf
, size_t size
)
1845 struct smbd_smb2_request
*req
;
1846 struct tevent_req
*subreq
;
1848 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
1849 (unsigned int)size
));
1851 status
= smbd_initialize_smb2(sconn
);
1852 if (!NT_STATUS_IS_OK(status
)) {
1853 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1857 status
= smbd_smb2_request_create(sconn
, inbuf
, size
, &req
);
1858 if (!NT_STATUS_IS_OK(status
)) {
1859 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1863 status
= smbd_smb2_request_setup_out(req
, (uint16_t)lp_maxmux());
1864 if (!NT_STATUS_IS_OK(status
)) {
1865 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1869 status
= smbd_smb2_request_dispatch(req
);
1870 if (!NT_STATUS_IS_OK(status
)) {
1871 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1875 /* ask for the next request */
1876 subreq
= smbd_smb2_request_read_send(sconn
, sconn
->smb2
.event_ctx
, sconn
);
1877 if (subreq
== NULL
) {
1878 smbd_server_connection_terminate(sconn
, "no memory for reading");
1881 tevent_req_set_callback(subreq
, smbd_smb2_request_incoming
, sconn
);
1884 static void smbd_smb2_request_incoming(struct tevent_req
*subreq
)
1886 uint16_t creds_requested
= 0;
1887 struct smbd_server_connection
*sconn
= tevent_req_callback_data(subreq
,
1888 struct smbd_server_connection
);
1890 struct smbd_smb2_request
*req
= NULL
;
1892 status
= smbd_smb2_request_read_recv(subreq
, sconn
, &req
);
1893 TALLOC_FREE(subreq
);
1894 if (!NT_STATUS_IS_OK(status
)) {
1895 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
1896 nt_errstr(status
)));
1897 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1901 if (req
->in
.nbt_hdr
[0] != 0x00) {
1902 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
1903 req
->in
.nbt_hdr
[0]));
1908 req
->current_idx
= 1;
1910 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
1911 req
->current_idx
, req
->in
.vector_count
));
1913 status
= smbd_smb2_request_validate(req
, &creds_requested
);
1914 if (!NT_STATUS_IS_OK(status
)) {
1915 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1919 status
= smbd_smb2_request_setup_out(req
, 5);
1920 if (!NT_STATUS_IS_OK(status
)) {
1921 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1925 status
= smbd_smb2_request_dispatch(req
);
1926 if (!NT_STATUS_IS_OK(status
)) {
1927 smbd_server_connection_terminate(sconn
, nt_errstr(status
));
1932 /* ask for the next request (this constructs the main loop) */
1933 subreq
= smbd_smb2_request_read_send(sconn
, sconn
->smb2
.event_ctx
, sconn
);
1934 if (subreq
== NULL
) {
1935 smbd_server_connection_terminate(sconn
, "no memory for reading");
1938 tevent_req_set_callback(subreq
, smbd_smb2_request_incoming
, sconn
);