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 "../source4/libcli/smb2/smb2_constants.h"
24 #include "../lib/tsocket/tsocket.h"
26 bool smbd_is_smb2_header(const uint8_t *inbuf
, size_t size
)
28 if (size
< (4 + SMB2_HDR_BODY
)) {
32 if (IVAL(inbuf
, 4) != SMB2_MAGIC
) {
39 static NTSTATUS
smbd_initialize_smb2(struct smbd_server_connection
*conn
)
44 TALLOC_FREE(conn
->smb1
.fde
);
46 conn
->smb2
.event_ctx
= smbd_event_context();
48 conn
->smb2
.recv_queue
= tevent_queue_create(conn
, "smb2 recv queue");
49 if (conn
->smb2
.recv_queue
== NULL
) {
50 return NT_STATUS_NO_MEMORY
;
53 conn
->smb2
.send_queue
= tevent_queue_create(conn
, "smb2 send queue");
54 if (conn
->smb2
.send_queue
== NULL
) {
55 return NT_STATUS_NO_MEMORY
;
58 conn
->smb2
.sessions
.idtree
= idr_init(conn
);
59 if (conn
->smb2
.sessions
.idtree
== NULL
) {
60 return NT_STATUS_NO_MEMORY
;
62 conn
->smb2
.sessions
.limit
= 0x0000FFFE;
63 conn
->smb2
.sessions
.list
= NULL
;
65 ret
= tstream_bsd_existing_socket(conn
, smbd_server_fd(),
68 status
= map_nt_error_from_unix(errno
);
72 /* Ensure child is set to non-blocking mode */
73 set_blocking(smbd_server_fd(),false);
77 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
78 #define _smb2_setlen(_buf,len) do { \
79 uint8_t *buf = (uint8_t *)_buf; \
81 buf[1] = ((len)&0xFF0000)>>16; \
82 buf[2] = ((len)&0xFF00)>>8; \
83 buf[3] = (len)&0xFF; \
86 static void smb2_setup_nbt_length(struct iovec
*vector
, int count
)
91 for (i
=1; i
< count
; i
++) {
92 len
+= vector
[i
].iov_len
;
95 _smb2_setlen(vector
[0].iov_base
, len
);
98 static NTSTATUS
smbd_smb2_request_create(struct smbd_server_connection
*conn
,
99 const uint8_t *inbuf
, size_t size
,
100 struct smbd_smb2_request
**_req
)
102 TALLOC_CTX
*mem_pool
;
103 struct smbd_smb2_request
*req
;
104 uint32_t protocol_version
;
105 const uint8_t *inhdr
= NULL
;
108 uint32_t next_command_ofs
;
110 if (size
< (4 + SMB2_HDR_BODY
+ 2)) {
111 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size
));
112 return NT_STATUS_INVALID_PARAMETER
;
117 protocol_version
= IVAL(inhdr
, SMB2_HDR_PROTOCOL_ID
);
118 if (protocol_version
!= SMB2_MAGIC
) {
119 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
121 return NT_STATUS_INVALID_PARAMETER
;
124 cmd
= SVAL(inhdr
, SMB2_HDR_OPCODE
);
125 if (cmd
!= SMB2_OP_NEGPROT
) {
126 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
128 return NT_STATUS_INVALID_PARAMETER
;
131 next_command_ofs
= IVAL(inhdr
, SMB2_HDR_NEXT_COMMAND
);
132 if (next_command_ofs
!= 0) {
133 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
135 return NT_STATUS_INVALID_PARAMETER
;
138 mem_pool
= talloc_pool(conn
, 8192);
139 if (mem_pool
== NULL
) {
140 return NT_STATUS_NO_MEMORY
;
143 req
= talloc_zero(mem_pool
, struct smbd_smb2_request
);
145 talloc_free(mem_pool
);
146 return NT_STATUS_NO_MEMORY
;
148 req
->mem_pool
= mem_pool
;
151 talloc_steal(req
, inbuf
);
153 req
->in
.vector
= talloc_array(req
, struct iovec
, 4);
154 if (req
->in
.vector
== NULL
) {
155 talloc_free(mem_pool
);
156 return NT_STATUS_NO_MEMORY
;
158 req
->in
.vector_count
= 4;
160 memcpy(req
->in
.nbt_hdr
, inbuf
, 4);
163 req
->in
.vector
[0].iov_base
= (void *)req
->in
.nbt_hdr
;
164 req
->in
.vector
[0].iov_len
= 4;
165 ofs
+= req
->in
.vector
[0].iov_len
;
167 req
->in
.vector
[1].iov_base
= (void *)(inbuf
+ ofs
);
168 req
->in
.vector
[1].iov_len
= SMB2_HDR_BODY
;
169 ofs
+= req
->in
.vector
[1].iov_len
;
171 req
->in
.vector
[2].iov_base
= (void *)(inbuf
+ ofs
);
172 req
->in
.vector
[2].iov_len
= SVAL(inbuf
, ofs
) & 0xFFFE;
173 ofs
+= req
->in
.vector
[2].iov_len
;
176 return NT_STATUS_INVALID_PARAMETER
;
179 req
->in
.vector
[3].iov_base
= (void *)(inbuf
+ ofs
);
180 req
->in
.vector
[3].iov_len
= size
- ofs
;
181 ofs
+= req
->in
.vector
[3].iov_len
;
183 req
->current_idx
= 1;
189 static NTSTATUS
smbd_smb2_request_validate(struct smbd_smb2_request
*req
)
193 bool compound_related
= false;
195 count
= req
->in
.vector_count
;
198 /* It's not a SMB2 request */
199 return NT_STATUS_INVALID_PARAMETER
;
202 for (idx
=1; idx
< count
; idx
+= 3) {
203 const uint8_t *inhdr
= NULL
;
206 if (req
->in
.vector
[idx
].iov_len
!= SMB2_HDR_BODY
) {
207 return NT_STATUS_INVALID_PARAMETER
;
210 if (req
->in
.vector
[idx
+1].iov_len
< 2) {
211 return NT_STATUS_INVALID_PARAMETER
;
214 inhdr
= (const uint8_t *)req
->in
.vector
[idx
].iov_base
;
216 /* setup the SMB2 header */
217 if (IVAL(inhdr
, SMB2_HDR_PROTOCOL_ID
) != SMB2_MAGIC
) {
218 return NT_STATUS_INVALID_PARAMETER
;
221 flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
224 * the 1st request should never have the
225 * SMB2_HDR_FLAG_CHAINED flag set
227 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
228 req
->next_status
= NT_STATUS_INVALID_PARAMETER
;
231 } else if (idx
== 4) {
233 * the 2nd request triggers related vs. unrelated
234 * compounded requests
236 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
237 compound_related
= true;
239 } else if (idx
> 4) {
241 * all other requests should match the 2nd one
243 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
244 if (!compound_related
) {
246 NT_STATUS_INVALID_PARAMETER
;
250 if (compound_related
) {
252 NT_STATUS_INVALID_PARAMETER
;
262 static NTSTATUS
smbd_smb2_request_setup_out(struct smbd_smb2_request
*req
)
264 struct iovec
*vector
;
268 count
= req
->in
.vector_count
;
269 vector
= talloc_array(req
, struct iovec
, count
);
270 if (vector
== NULL
) {
271 return NT_STATUS_NO_MEMORY
;
274 vector
[0].iov_base
= req
->out
.nbt_hdr
;
275 vector
[0].iov_len
= 4;
276 SIVAL(req
->out
.nbt_hdr
, 0, 0);
278 for (idx
=1; idx
< count
; idx
+= 3) {
279 const uint8_t *inhdr
= NULL
;
281 uint8_t *outhdr
= NULL
;
282 uint8_t *outbody
= NULL
;
283 uint32_t next_command_ofs
= 0;
284 struct iovec
*current
= &vector
[idx
];
286 if ((idx
+ 3) < count
) {
287 /* we have a next command */
288 next_command_ofs
= SMB2_HDR_BODY
+ 8;
291 inhdr
= (const uint8_t *)req
->in
.vector
[idx
].iov_base
;
292 in_flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
294 outhdr
= talloc_array(vector
, uint8_t,
296 if (outhdr
== NULL
) {
297 return NT_STATUS_NO_MEMORY
;
300 outbody
= outhdr
+ SMB2_HDR_BODY
;
302 current
[0].iov_base
= (void *)outhdr
;
303 current
[0].iov_len
= SMB2_HDR_BODY
;
305 current
[1].iov_base
= (void *)outbody
;
306 current
[1].iov_len
= 8;
308 current
[2].iov_base
= NULL
;
309 current
[2].iov_len
= 0;
311 /* setup the SMB2 header */
312 SIVAL(outhdr
, SMB2_HDR_PROTOCOL_ID
, SMB2_MAGIC
);
313 SSVAL(outhdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
314 SSVAL(outhdr
, SMB2_HDR_EPOCH
, 0);
315 SIVAL(outhdr
, SMB2_HDR_STATUS
,
316 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR
));
317 SSVAL(outhdr
, SMB2_HDR_OPCODE
,
318 SVAL(inhdr
, SMB2_HDR_OPCODE
));
319 /* Make up a number for now... JRA. FIXME ! FIXME !*/
320 SSVAL(outhdr
, SMB2_HDR_CREDIT
, 20);
321 SIVAL(outhdr
, SMB2_HDR_FLAGS
,
322 IVAL(inhdr
, SMB2_HDR_FLAGS
) | SMB2_HDR_FLAG_REDIRECT
);
323 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, next_command_ofs
);
324 SBVAL(outhdr
, SMB2_HDR_MESSAGE_ID
,
325 BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
));
326 SIVAL(outhdr
, SMB2_HDR_PID
,
327 IVAL(inhdr
, SMB2_HDR_PID
));
328 SIVAL(outhdr
, SMB2_HDR_TID
,
329 IVAL(inhdr
, SMB2_HDR_TID
));
330 SBVAL(outhdr
, SMB2_HDR_SESSION_ID
,
331 BVAL(inhdr
, SMB2_HDR_SESSION_ID
));
332 memset(outhdr
+ SMB2_HDR_SIGNATURE
, 0, 16);
334 /* setup error body header */
335 SSVAL(outbody
, 0x00, 0x08 + 1);
336 SSVAL(outbody
, 0x02, 0);
337 SIVAL(outbody
, 0x04, 0);
340 req
->out
.vector
= vector
;
341 req
->out
.vector_count
= count
;
343 /* setup the length of the NBT packet */
344 smb2_setup_nbt_length(req
->out
.vector
, req
->out
.vector_count
);
349 void smbd_server_connection_terminate_ex(struct smbd_server_connection
*sconn
,
351 const char *location
)
353 DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
355 exit_server_cleanly(reason
);
358 static NTSTATUS
smbd_smb2_request_dispatch(struct smbd_smb2_request
*req
)
360 const uint8_t *inhdr
;
361 int i
= req
->current_idx
;
365 NTSTATUS session_status
;
367 inhdr
= (const uint8_t *)req
->in
.vector
[i
].iov_base
;
369 /* TODO: verify more things */
371 flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
372 opcode
= IVAL(inhdr
, SMB2_HDR_OPCODE
);
373 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode
));
375 #define TMP_SMB2_ALLOWED_FLAGS ( \
376 SMB2_HDR_FLAG_CHAINED | \
377 SMB2_HDR_FLAG_SIGNED | \
379 if ((flags
& ~TMP_SMB2_ALLOWED_FLAGS
) != 0) {
380 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
382 #undef TMP_SMB2_ALLOWED_FLAGS
384 session_status
= smbd_smb2_request_check_session(req
);
386 req
->do_signing
= false;
387 if (flags
& SMB2_HDR_FLAG_SIGNED
) {
388 if (!NT_STATUS_IS_OK(session_status
)) {
389 return smbd_smb2_request_error(req
, session_status
);
392 req
->do_signing
= true;
393 status
= smb2_signing_check_pdu(req
->session
->session_key
,
394 &req
->in
.vector
[i
], 3);
395 if (!NT_STATUS_IS_OK(status
)) {
396 return smbd_smb2_request_error(req
, status
);
398 } else if (req
->session
&& req
->session
->do_signing
) {
399 return smbd_smb2_request_error(req
, NT_STATUS_ACCESS_DENIED
);
402 if (flags
& SMB2_HDR_FLAG_CHAINED
) {
404 * This check is mostly for giving the correct error code
405 * for compounded requests.
407 * TODO: we may need to move this after the session
410 if (!NT_STATUS_IS_OK(req
->next_status
)) {
411 return smbd_smb2_request_error(req
, req
->next_status
);
414 req
->compat_chain_fsp
= NULL
;
418 case SMB2_OP_NEGPROT
:
419 return smbd_smb2_request_process_negprot(req
);
421 case SMB2_OP_SESSSETUP
:
422 return smbd_smb2_request_process_sesssetup(req
);
425 if (!NT_STATUS_IS_OK(session_status
)) {
426 return smbd_smb2_request_error(req
, session_status
);
428 return smbd_smb2_request_process_logoff(req
);
431 if (!NT_STATUS_IS_OK(session_status
)) {
432 return smbd_smb2_request_error(req
, session_status
);
434 status
= smbd_smb2_request_check_session(req
);
435 if (!NT_STATUS_IS_OK(status
)) {
436 return smbd_smb2_request_error(req
, status
);
438 return smbd_smb2_request_process_tcon(req
);
441 if (!NT_STATUS_IS_OK(session_status
)) {
442 return smbd_smb2_request_error(req
, session_status
);
444 status
= smbd_smb2_request_check_tcon(req
);
445 if (!NT_STATUS_IS_OK(status
)) {
446 return smbd_smb2_request_error(req
, status
);
448 return smbd_smb2_request_process_tdis(req
);
451 if (!NT_STATUS_IS_OK(session_status
)) {
452 return smbd_smb2_request_error(req
, session_status
);
454 status
= smbd_smb2_request_check_tcon(req
);
455 if (!NT_STATUS_IS_OK(status
)) {
456 return smbd_smb2_request_error(req
, status
);
458 return smbd_smb2_request_process_create(req
);
461 if (!NT_STATUS_IS_OK(session_status
)) {
462 return smbd_smb2_request_error(req
, session_status
);
464 status
= smbd_smb2_request_check_tcon(req
);
465 if (!NT_STATUS_IS_OK(status
)) {
466 return smbd_smb2_request_error(req
, status
);
468 return smbd_smb2_request_process_close(req
);
471 if (!NT_STATUS_IS_OK(session_status
)) {
472 return smbd_smb2_request_error(req
, session_status
);
474 status
= smbd_smb2_request_check_tcon(req
);
475 if (!NT_STATUS_IS_OK(status
)) {
476 return smbd_smb2_request_error(req
, status
);
478 return smbd_smb2_request_process_flush(req
);
481 if (!NT_STATUS_IS_OK(session_status
)) {
482 return smbd_smb2_request_error(req
, session_status
);
484 status
= smbd_smb2_request_check_tcon(req
);
485 if (!NT_STATUS_IS_OK(status
)) {
486 return smbd_smb2_request_error(req
, status
);
488 return smbd_smb2_request_process_read(req
);
491 if (!NT_STATUS_IS_OK(session_status
)) {
492 return smbd_smb2_request_error(req
, session_status
);
494 status
= smbd_smb2_request_check_tcon(req
);
495 if (!NT_STATUS_IS_OK(status
)) {
496 return smbd_smb2_request_error(req
, status
);
498 return smbd_smb2_request_process_write(req
);
501 if (!NT_STATUS_IS_OK(session_status
)) {
502 return smbd_smb2_request_error(req
, session_status
);
504 status
= smbd_smb2_request_check_tcon(req
);
505 if (!NT_STATUS_IS_OK(status
)) {
506 return smbd_smb2_request_error(req
, status
);
508 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
511 if (!NT_STATUS_IS_OK(session_status
)) {
512 return smbd_smb2_request_error(req
, session_status
);
514 status
= smbd_smb2_request_check_tcon(req
);
515 if (!NT_STATUS_IS_OK(status
)) {
516 return smbd_smb2_request_error(req
, status
);
518 return smbd_smb2_request_process_ioctl(req
);
521 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
523 case SMB2_OP_KEEPALIVE
:
524 return smbd_smb2_request_process_keepalive(req
);
527 if (!NT_STATUS_IS_OK(session_status
)) {
528 return smbd_smb2_request_error(req
, session_status
);
530 status
= smbd_smb2_request_check_tcon(req
);
531 if (!NT_STATUS_IS_OK(status
)) {
532 return smbd_smb2_request_error(req
, status
);
534 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
537 if (!NT_STATUS_IS_OK(session_status
)) {
538 return smbd_smb2_request_error(req
, session_status
);
540 status
= smbd_smb2_request_check_tcon(req
);
541 if (!NT_STATUS_IS_OK(status
)) {
542 return smbd_smb2_request_error(req
, status
);
544 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
546 case SMB2_OP_GETINFO
:
547 if (!NT_STATUS_IS_OK(session_status
)) {
548 return smbd_smb2_request_error(req
, session_status
);
550 status
= smbd_smb2_request_check_tcon(req
);
551 if (!NT_STATUS_IS_OK(status
)) {
552 return smbd_smb2_request_error(req
, status
);
554 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
556 case SMB2_OP_SETINFO
:
557 if (!NT_STATUS_IS_OK(session_status
)) {
558 return smbd_smb2_request_error(req
, session_status
);
560 status
= smbd_smb2_request_check_tcon(req
);
561 if (!NT_STATUS_IS_OK(status
)) {
562 return smbd_smb2_request_error(req
, status
);
564 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
567 if (!NT_STATUS_IS_OK(session_status
)) {
568 return smbd_smb2_request_error(req
, session_status
);
570 status
= smbd_smb2_request_check_tcon(req
);
571 if (!NT_STATUS_IS_OK(status
)) {
572 return smbd_smb2_request_error(req
, status
);
574 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
577 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
580 static void smbd_smb2_request_dispatch_compound(struct tevent_req
*subreq
);
581 static void smbd_smb2_request_writev_done(struct tevent_req
*subreq
);
583 static NTSTATUS
smbd_smb2_request_reply(struct smbd_smb2_request
*req
)
585 struct tevent_req
*subreq
;
587 smb2_setup_nbt_length(req
->out
.vector
, req
->out
.vector_count
);
589 if (req
->do_signing
) {
590 int i
= req
->current_idx
;
592 status
= smb2_signing_sign_pdu(req
->session
->session_key
,
593 &req
->out
.vector
[i
], 3);
594 if (!NT_STATUS_IS_OK(status
)) {
599 req
->current_idx
+= 3;
601 if (req
->current_idx
< req
->out
.vector_count
) {
602 struct timeval zero
= timeval_zero();
603 subreq
= tevent_wakeup_send(req
,
604 req
->conn
->smb2
.event_ctx
,
606 if (subreq
== NULL
) {
607 return NT_STATUS_NO_MEMORY
;
609 tevent_req_set_callback(subreq
,
610 smbd_smb2_request_dispatch_compound
,
616 subreq
= tstream_writev_queue_send(req
,
617 req
->conn
->smb2
.event_ctx
,
618 req
->conn
->smb2
.stream
,
619 req
->conn
->smb2
.send_queue
,
621 req
->out
.vector_count
);
622 if (subreq
== NULL
) {
623 return NT_STATUS_NO_MEMORY
;
625 tevent_req_set_callback(subreq
, smbd_smb2_request_writev_done
, req
);
630 static void smbd_smb2_request_dispatch_compound(struct tevent_req
*subreq
)
632 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
633 struct smbd_smb2_request
);
634 struct smbd_server_connection
*conn
= req
->conn
;
637 tevent_wakeup_recv(subreq
);
640 DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n",
641 req
->current_idx
, req
->in
.vector_count
));
643 status
= smbd_smb2_request_dispatch(req
);
644 if (!NT_STATUS_IS_OK(status
)) {
645 smbd_server_connection_terminate(conn
, nt_errstr(status
));
650 static void smbd_smb2_request_writev_done(struct tevent_req
*subreq
)
652 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
653 struct smbd_smb2_request
);
654 struct smbd_server_connection
*conn
= req
->conn
;
657 TALLOC_CTX
*mem_pool
;
659 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
662 NTSTATUS status
= map_nt_error_from_unix(sys_errno
);
663 smbd_server_connection_terminate(conn
, nt_errstr(status
));
667 mem_pool
= req
->mem_pool
;
669 talloc_free(mem_pool
);
672 NTSTATUS
smbd_smb2_request_error_ex(struct smbd_smb2_request
*req
,
675 const char *location
)
679 int i
= req
->current_idx
;
681 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
682 i
, nt_errstr(status
), info
? " +info" : "",
685 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
687 SIVAL(outhdr
, SMB2_HDR_STATUS
, NT_STATUS_V(status
));
689 outbody
= outhdr
+ SMB2_HDR_BODY
;
691 req
->out
.vector
[i
+1].iov_base
= (void *)outbody
;
692 req
->out
.vector
[i
+1].iov_len
= 8;
695 SIVAL(outbody
, 0x04, info
->length
);
696 req
->out
.vector
[i
+2].iov_base
= (void *)info
->data
;
697 req
->out
.vector
[i
+2].iov_len
= info
->length
;
699 req
->out
.vector
[i
+2].iov_base
= NULL
;
700 req
->out
.vector
[i
+2].iov_len
= 0;
704 * if a request fails, all other remaining
705 * compounded requests should fail too
707 req
->next_status
= NT_STATUS_INVALID_PARAMETER
;
709 return smbd_smb2_request_reply(req
);
712 NTSTATUS
smbd_smb2_request_done_ex(struct smbd_smb2_request
*req
,
714 DATA_BLOB body
, DATA_BLOB
*dyn
,
715 const char *location
)
719 int i
= req
->current_idx
;
720 uint32_t next_command_ofs
;
722 DEBUG(10,("smbd_smb2_request_done_ex: "
723 "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
724 i
, nt_errstr(status
), (unsigned int)body
.length
,
726 (unsigned int)(dyn
? dyn
->length
: 0),
729 if (body
.length
< 2) {
730 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
733 if ((body
.length
% 2) != 0) {
734 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
737 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
738 /* the fallback dynamic buffer */
739 outdyn
= outhdr
+ SMB2_HDR_BODY
+ 8;
741 next_command_ofs
= IVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
);
742 SIVAL(outhdr
, SMB2_HDR_STATUS
, NT_STATUS_V(status
));
744 req
->out
.vector
[i
+1].iov_base
= (void *)body
.data
;
745 req
->out
.vector
[i
+1].iov_len
= body
.length
;
748 req
->out
.vector
[i
+2].iov_base
= (void *)dyn
->data
;
749 req
->out
.vector
[i
+2].iov_len
= dyn
->length
;
751 req
->out
.vector
[i
+2].iov_base
= NULL
;
752 req
->out
.vector
[i
+2].iov_len
= 0;
755 /* see if we need to recalculate the offset to the next response */
756 if (next_command_ofs
> 0) {
757 next_command_ofs
= SMB2_HDR_BODY
;
758 next_command_ofs
+= req
->out
.vector
[i
+1].iov_len
;
759 next_command_ofs
+= req
->out
.vector
[i
+2].iov_len
;
762 if ((next_command_ofs
% 8) != 0) {
763 size_t pad_size
= 8 - (next_command_ofs
% 8);
764 if (req
->out
.vector
[i
+2].iov_len
== 0) {
766 * if the dyn buffer is empty
767 * we can use it to add padding
771 pad
= talloc_zero_array(req
->out
.vector
,
774 return smbd_smb2_request_error(req
,
775 NT_STATUS_NO_MEMORY
);
778 req
->out
.vector
[i
+2].iov_base
= (void *)pad
;
779 req
->out
.vector
[i
+2].iov_len
= pad_size
;
782 * For now we copy the dynamic buffer
783 * and add the padding to the new buffer
790 old_size
= req
->out
.vector
[i
+2].iov_len
;
791 old_dyn
= (uint8_t *)req
->out
.vector
[i
+2].iov_base
;
793 new_size
= old_size
+ pad_size
;
794 new_dyn
= talloc_array(req
->out
.vector
,
796 if (new_dyn
== NULL
) {
797 return smbd_smb2_request_error(req
,
798 NT_STATUS_NO_MEMORY
);
801 memcpy(new_dyn
, old_dyn
, old_size
);
802 memset(new_dyn
+ old_size
, 0, pad_size
);
804 req
->out
.vector
[i
+2].iov_base
= (void *)new_dyn
;
805 req
->out
.vector
[i
+2].iov_len
= new_size
;
807 TALLOC_FREE(old_dyn
);
809 next_command_ofs
+= pad_size
;
812 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, next_command_ofs
);
814 return smbd_smb2_request_reply(req
);
817 struct smbd_smb2_request_read_state
{
819 bool asked_for_header
;
820 struct smbd_smb2_request
*smb2_req
;
823 static int smbd_smb2_request_next_vector(struct tstream_context
*stream
,
826 struct iovec
**_vector
,
828 static void smbd_smb2_request_read_done(struct tevent_req
*subreq
);
830 static struct tevent_req
*smbd_smb2_request_read_send(TALLOC_CTX
*mem_ctx
,
831 struct tevent_context
*ev
,
832 struct smbd_server_connection
*conn
)
834 struct tevent_req
*req
;
835 struct smbd_smb2_request_read_state
*state
;
836 struct tevent_req
*subreq
;
837 TALLOC_CTX
*mem_pool
;
839 req
= tevent_req_create(mem_ctx
, &state
,
840 struct smbd_smb2_request_read_state
);
845 state
->asked_for_header
= false;
847 mem_pool
= talloc_pool(state
, 8192);
848 if (tevent_req_nomem(mem_pool
, req
)) {
849 return tevent_req_post(req
, ev
);
852 state
->smb2_req
= talloc_zero(mem_pool
, struct smbd_smb2_request
);
853 if (tevent_req_nomem(state
->smb2_req
, req
)) {
854 return tevent_req_post(req
, ev
);
857 state
->smb2_req
->mem_pool
= mem_pool
;
858 state
->smb2_req
->conn
= conn
;
860 subreq
= tstream_readv_pdu_queue_send(state
, ev
, conn
->smb2
.stream
,
861 conn
->smb2
.recv_queue
,
862 smbd_smb2_request_next_vector
,
864 if (tevent_req_nomem(subreq
, req
)) {
865 return tevent_req_post(req
, ev
);
867 tevent_req_set_callback(subreq
, smbd_smb2_request_read_done
, req
);
872 static int smbd_smb2_request_next_vector(struct tstream_context
*stream
,
875 struct iovec
**_vector
,
878 struct smbd_smb2_request_read_state
*state
=
879 talloc_get_type_abort(private_data
,
880 struct smbd_smb2_request_read_state
);
881 struct smbd_smb2_request
*req
= state
->smb2_req
;
882 struct iovec
*vector
;
883 int idx
= req
->in
.vector_count
;
887 if (req
->in
.vector_count
== 0) {
889 * first we need to get the NBT header
891 req
->in
.vector
= talloc_array(req
, struct iovec
,
892 req
->in
.vector_count
+ 1);
893 if (req
->in
.vector
== NULL
) {
896 req
->in
.vector_count
+= 1;
898 req
->in
.vector
[idx
].iov_base
= (void *)req
->in
.nbt_hdr
;
899 req
->in
.vector
[idx
].iov_len
= 4;
901 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
902 if (vector
== NULL
) {
906 vector
[0] = req
->in
.vector
[idx
];
913 if (req
->in
.vector_count
== 1) {
915 * Now we analyze the NBT header
917 state
->missing
= smb2_len(req
->in
.vector
[0].iov_base
);
919 if (state
->missing
== 0) {
920 /* if there're no remaining bytes, we're done */
926 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
928 req
->in
.vector_count
+ 1);
929 if (req
->in
.vector
== NULL
) {
932 req
->in
.vector_count
+= 1;
934 if (CVAL(req
->in
.vector
[0].iov_base
, 0) != 0) {
936 * it's a special NBT message,
937 * so get all remaining bytes
939 len
= state
->missing
;
940 } else if (state
->missing
< (SMB2_HDR_BODY
+ 2)) {
942 * it's an invalid message, just read what we can get
943 * and let the caller handle the error
945 len
= state
->missing
;
948 * We assume it's a SMB2 request,
949 * and we first get the header and the
950 * first 2 bytes (the struct size) of the body
952 len
= SMB2_HDR_BODY
+ 2;
954 state
->asked_for_header
= true;
957 state
->missing
-= len
;
959 buf
= talloc_array(req
->in
.vector
, uint8_t, len
);
964 req
->in
.vector
[idx
].iov_base
= (void *)buf
;
965 req
->in
.vector
[idx
].iov_len
= len
;
967 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
968 if (vector
== NULL
) {
972 vector
[0] = req
->in
.vector
[idx
];
979 if (state
->missing
== 0) {
980 /* if there're no remaining bytes, we're done */
986 if (state
->asked_for_header
) {
989 size_t next_command_ofs
;
994 bool invalid
= false;
996 state
->asked_for_header
= false;
999 * We got the SMB2 header and the first 2 bytes
1000 * of the body. We fix the size to just the header
1001 * and manually copy the 2 first bytes to the body section
1003 req
->in
.vector
[idx
-1].iov_len
= SMB2_HDR_BODY
;
1004 hdr
= (const uint8_t *)req
->in
.vector
[idx
-1].iov_base
;
1006 /* allocate vectors for body and dynamic areas */
1007 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
1009 req
->in
.vector_count
+ 2);
1010 if (req
->in
.vector
== NULL
) {
1013 req
->in
.vector_count
+= 2;
1015 full_size
= state
->missing
+ SMB2_HDR_BODY
+ 2;
1016 next_command_ofs
= IVAL(hdr
, SMB2_HDR_NEXT_COMMAND
);
1017 body_size
= SVAL(hdr
, SMB2_HDR_BODY
);
1019 if (next_command_ofs
!= 0) {
1020 if (next_command_ofs
< (SMB2_HDR_BODY
+ 2)) {
1022 * this is invalid, just return a zero
1023 * body and let the caller deal with the error
1026 } else if (next_command_ofs
> full_size
) {
1028 * this is invalid, just return a zero
1029 * body and let the caller deal with the error
1033 full_size
= next_command_ofs
;
1038 if (body_size
< 2) {
1040 * this is invalid, just return a zero
1041 * body and let the caller deal with the error
1044 } else if (body_size
> (full_size
- SMB2_HDR_BODY
)) {
1046 * this is invalid, just return a zero
1047 * body and let the caller deal with the error
1054 /* the caller should check this */
1058 if ((body_size
% 2) != 0) {
1062 dyn_size
= full_size
- (SMB2_HDR_BODY
+ body_size
);
1064 state
->missing
-= (body_size
- 2) + dyn_size
;
1066 body
= talloc_array(req
->in
.vector
, uint8_t, body_size
);
1071 dyn
= talloc_array(req
->in
.vector
, uint8_t, dyn_size
);
1076 req
->in
.vector
[idx
].iov_base
= (void *)body
;
1077 req
->in
.vector
[idx
].iov_len
= body_size
;
1078 req
->in
.vector
[idx
+1].iov_base
= (void *)dyn
;
1079 req
->in
.vector
[idx
+1].iov_len
= dyn_size
;
1081 vector
= talloc_array(mem_ctx
, struct iovec
, 2);
1082 if (vector
== NULL
) {
1087 * the first 2 bytes of the body were already fetched
1088 * together with the header
1090 memcpy(body
, hdr
+ SMB2_HDR_BODY
, 2);
1091 vector
[0].iov_base
= body
+ 2;
1092 vector
[0].iov_len
= req
->in
.vector
[idx
].iov_len
- 2;
1094 vector
[1] = req
->in
.vector
[idx
+1];
1102 * when we endup here, we're looking for a new SMB2 request
1103 * next. And we ask for its header and the first 2 bytes of
1104 * the body (like we did for the first SMB2 request).
1107 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
1109 req
->in
.vector_count
+ 1);
1110 if (req
->in
.vector
== NULL
) {
1113 req
->in
.vector_count
+= 1;
1116 * We assume it's a SMB2 request,
1117 * and we first get the header and the
1118 * first 2 bytes (the struct size) of the body
1120 len
= SMB2_HDR_BODY
+ 2;
1122 if (len
> state
->missing
) {
1123 /* let the caller handle the error */
1124 len
= state
->missing
;
1127 state
->missing
-= len
;
1128 state
->asked_for_header
= true;
1130 buf
= talloc_array(req
->in
.vector
, uint8_t, len
);
1135 req
->in
.vector
[idx
].iov_base
= (void *)buf
;
1136 req
->in
.vector
[idx
].iov_len
= len
;
1138 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
1139 if (vector
== NULL
) {
1143 vector
[0] = req
->in
.vector
[idx
];
1150 static void smbd_smb2_request_read_done(struct tevent_req
*subreq
)
1152 struct tevent_req
*req
=
1153 tevent_req_callback_data(subreq
,
1159 ret
= tstream_readv_pdu_queue_recv(subreq
, &sys_errno
);
1161 status
= map_nt_error_from_unix(sys_errno
);
1162 tevent_req_nterror(req
, status
);
1166 tevent_req_done(req
);
1169 static NTSTATUS
smbd_smb2_request_read_recv(struct tevent_req
*req
,
1170 TALLOC_CTX
*mem_ctx
,
1171 struct smbd_smb2_request
**_smb2_req
)
1173 struct smbd_smb2_request_read_state
*state
=
1174 tevent_req_data(req
,
1175 struct smbd_smb2_request_read_state
);
1178 if (tevent_req_is_nterror(req
, &status
)) {
1179 tevent_req_received(req
);
1183 talloc_steal(mem_ctx
, state
->smb2_req
->mem_pool
);
1184 *_smb2_req
= state
->smb2_req
;
1185 tevent_req_received(req
);
1186 return NT_STATUS_OK
;
1189 static void smbd_smb2_request_incoming(struct tevent_req
*subreq
);
1191 void smbd_smb2_first_negprot(struct smbd_server_connection
*conn
,
1192 const uint8_t *inbuf
, size_t size
)
1195 struct smbd_smb2_request
*req
;
1196 struct tevent_req
*subreq
;
1198 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
1199 (unsigned int)size
));
1201 status
= smbd_initialize_smb2(conn
);
1202 if (!NT_STATUS_IS_OK(status
)) {
1203 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1207 status
= smbd_smb2_request_create(conn
, inbuf
, size
, &req
);
1208 if (!NT_STATUS_IS_OK(status
)) {
1209 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1213 status
= smbd_smb2_request_setup_out(req
);
1214 if (!NT_STATUS_IS_OK(status
)) {
1215 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1219 status
= smbd_smb2_request_dispatch(req
);
1220 if (!NT_STATUS_IS_OK(status
)) {
1221 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1225 /* ask for the next request */
1226 subreq
= smbd_smb2_request_read_send(conn
,conn
->smb2
.event_ctx
, conn
);
1227 if (subreq
== NULL
) {
1228 smbd_server_connection_terminate(conn
, "no memory for reading");
1231 tevent_req_set_callback(subreq
, smbd_smb2_request_incoming
, conn
);
1234 static void smbd_smb2_request_incoming(struct tevent_req
*subreq
)
1236 struct smbd_server_connection
*conn
= tevent_req_callback_data(subreq
,
1237 struct smbd_server_connection
);
1239 struct smbd_smb2_request
*req
;
1241 status
= smbd_smb2_request_read_recv(subreq
, conn
, &req
);
1242 TALLOC_FREE(subreq
);
1243 if (!NT_STATUS_IS_OK(status
)) {
1244 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1248 if (req
->in
.nbt_hdr
[0] != 0x00) {
1249 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
1250 req
->in
.nbt_hdr
[0]));
1251 talloc_free(req
->mem_pool
);
1256 req
->current_idx
= 1;
1258 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
1259 req
->current_idx
, req
->in
.vector_count
));
1261 status
= smbd_smb2_request_validate(req
);
1262 if (!NT_STATUS_IS_OK(status
)) {
1263 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1267 status
= smbd_smb2_request_setup_out(req
);
1268 if (!NT_STATUS_IS_OK(status
)) {
1269 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1273 status
= smbd_smb2_request_dispatch(req
);
1274 if (!NT_STATUS_IS_OK(status
)) {
1275 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1280 /* ask for the next request (this constructs the main loop) */
1281 subreq
= smbd_smb2_request_read_send(conn
,conn
->smb2
.event_ctx
, conn
);
1282 if (subreq
== NULL
) {
1283 smbd_server_connection_terminate(conn
, "no memory for reading");
1286 tevent_req_set_callback(subreq
, smbd_smb2_request_incoming
, conn
);