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
= 0x00FFFFFF;
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_setup_out(struct smbd_smb2_request
*req
)
191 struct iovec
*vector
;
195 count
= req
->in
.vector_count
;
196 vector
= talloc_array(req
, struct iovec
, count
);
197 if (vector
== NULL
) {
198 return NT_STATUS_NO_MEMORY
;
201 vector
[0].iov_base
= req
->out
.nbt_hdr
;
202 vector
[0].iov_len
= 4;
203 SIVAL(req
->out
.nbt_hdr
, 0, 0);
205 for (idx
=1; idx
< count
; idx
+= 3) {
206 const uint8_t *inhdr
= NULL
;
207 uint8_t *outhdr
= NULL
;
208 uint8_t *outbody
= NULL
;
209 uint8_t *outdyn
= NULL
;
210 size_t outdyn_size
= 1;
211 uint32_t next_command_ofs
= 0;
212 struct iovec
*current
= &vector
[idx
];
214 if ((idx
+ 3) < count
) {
215 /* we have a next command */
216 next_command_ofs
= SMB2_HDR_BODY
+ 8 + 8;
220 inhdr
= (const uint8_t *)req
->in
.vector
[idx
].iov_base
;
222 outhdr
= talloc_array(vector
, uint8_t,
223 SMB2_HDR_BODY
+ 8 + outdyn_size
);
224 if (outhdr
== NULL
) {
225 return NT_STATUS_NO_MEMORY
;
228 outbody
= outhdr
+ SMB2_HDR_BODY
;
229 outdyn
= outbody
+ 8;
231 current
[0].iov_base
= (void *)outhdr
;
232 current
[0].iov_len
= SMB2_HDR_BODY
;
234 current
[1].iov_base
= (void *)outbody
;
235 current
[1].iov_len
= 8;
237 current
[2].iov_base
= (void *)outdyn
;
238 current
[2].iov_len
= outdyn_size
;
240 /* setup the SMB2 header */
241 SIVAL(outhdr
, SMB2_HDR_PROTOCOL_ID
, SMB2_MAGIC
);
242 SSVAL(outhdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
243 SSVAL(outhdr
, SMB2_HDR_EPOCH
, 0);
244 SIVAL(outhdr
, SMB2_HDR_STATUS
,
245 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR
));
246 SSVAL(outhdr
, SMB2_HDR_OPCODE
,
247 SVAL(inhdr
, SMB2_HDR_OPCODE
));
248 SSVAL(outhdr
, SMB2_HDR_CREDIT
, 0);
249 SIVAL(outhdr
, SMB2_HDR_FLAGS
, SMB2_HDR_FLAG_REDIRECT
);
250 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, next_command_ofs
);
251 SBVAL(outhdr
, SMB2_HDR_MESSAGE_ID
,
252 BVAL(inhdr
, SMB2_HDR_MESSAGE_ID
));
253 SIVAL(outhdr
, SMB2_HDR_PID
,
254 IVAL(inhdr
, SMB2_HDR_PID
));
255 SIVAL(outhdr
, SMB2_HDR_TID
,
256 IVAL(inhdr
, SMB2_HDR_TID
));
257 SBVAL(outhdr
, SMB2_HDR_SESSION_ID
,
258 BVAL(inhdr
, SMB2_HDR_SESSION_ID
));
259 memset(outhdr
+ SMB2_HDR_SIGNATURE
, 0, 16);
261 /* setup error body header */
262 SSVAL(outbody
, 0x00, 9);
263 SSVAL(outbody
, 0x02, 0);
264 SIVAL(outbody
, 0x04, 0);
266 /* setup the dynamic part */
267 SCVAL(outdyn
, 0x00, 0);
270 req
->out
.vector
= vector
;
271 req
->out
.vector_count
= count
;
273 /* setup the length of the NBT packet */
274 smb2_setup_nbt_length(req
->out
.vector
, req
->out
.vector_count
);
279 static void smbd_server_connection_terminate(struct smbd_server_connection
*conn
,
282 DEBUG(10,("smbd_server_connection_terminate: reason[%s]\n", reason
));
283 exit_server_cleanly(reason
);
286 static NTSTATUS
smbd_smb2_request_dispatch(struct smbd_smb2_request
*req
)
288 const uint8_t *inhdr
;
289 int i
= req
->current_idx
;
293 NTSTATUS session_status
;
295 inhdr
= (const uint8_t *)req
->in
.vector
[i
].iov_base
;
297 /* TODO: verify more things */
299 flags
= IVAL(inhdr
, SMB2_HDR_FLAGS
);
300 opcode
= IVAL(inhdr
, SMB2_HDR_OPCODE
);
301 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode
));
303 #define TMP_SMB2_ALLOWED_FLAGS ( \
304 SMB2_HDR_FLAG_CHAINED | \
305 SMB2_HDR_FLAG_SIGNED | \
307 if ((flags
& ~TMP_SMB2_ALLOWED_FLAGS
) != 0) {
308 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
310 #undef TMP_SMB2_ALLOWED_FLAGS
312 session_status
= smbd_smb2_request_check_session(req
);
314 req
->do_signing
= false;
315 if (flags
& SMB2_HDR_FLAG_SIGNED
) {
316 if (!NT_STATUS_IS_OK(session_status
)) {
317 return smbd_smb2_request_error(req
, session_status
);
320 req
->do_signing
= true;
321 status
= smb2_signing_check_pdu(req
->session
->session_key
,
322 &req
->in
.vector
[i
], 3);
323 if (!NT_STATUS_IS_OK(status
)) {
324 return smbd_smb2_request_error(req
, status
);
326 } else if (req
->session
&& req
->session
->do_signing
) {
327 return smbd_smb2_request_error(req
, NT_STATUS_ACCESS_DENIED
);
331 case SMB2_OP_NEGPROT
:
332 return smbd_smb2_request_process_negprot(req
);
334 case SMB2_OP_SESSSETUP
:
335 return smbd_smb2_request_process_sesssetup(req
);
338 if (!NT_STATUS_IS_OK(session_status
)) {
339 return smbd_smb2_request_error(req
, session_status
);
341 return smbd_smb2_request_process_logoff(req
);
344 if (!NT_STATUS_IS_OK(session_status
)) {
345 return smbd_smb2_request_error(req
, session_status
);
347 status
= smbd_smb2_request_check_session(req
);
348 if (!NT_STATUS_IS_OK(status
)) {
349 return smbd_smb2_request_error(req
, status
);
351 return smbd_smb2_request_process_tcon(req
);
354 if (!NT_STATUS_IS_OK(session_status
)) {
355 return smbd_smb2_request_error(req
, session_status
);
357 status
= smbd_smb2_request_check_tcon(req
);
358 if (!NT_STATUS_IS_OK(status
)) {
359 return smbd_smb2_request_error(req
, status
);
361 return smbd_smb2_request_process_tdis(req
);
364 if (!NT_STATUS_IS_OK(session_status
)) {
365 return smbd_smb2_request_error(req
, session_status
);
367 status
= smbd_smb2_request_check_tcon(req
);
368 if (!NT_STATUS_IS_OK(status
)) {
369 return smbd_smb2_request_error(req
, status
);
371 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
374 if (!NT_STATUS_IS_OK(session_status
)) {
375 return smbd_smb2_request_error(req
, session_status
);
377 status
= smbd_smb2_request_check_tcon(req
);
378 if (!NT_STATUS_IS_OK(status
)) {
379 return smbd_smb2_request_error(req
, status
);
381 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
384 if (!NT_STATUS_IS_OK(session_status
)) {
385 return smbd_smb2_request_error(req
, session_status
);
387 status
= smbd_smb2_request_check_tcon(req
);
388 if (!NT_STATUS_IS_OK(status
)) {
389 return smbd_smb2_request_error(req
, status
);
391 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
394 if (!NT_STATUS_IS_OK(session_status
)) {
395 return smbd_smb2_request_error(req
, session_status
);
397 status
= smbd_smb2_request_check_tcon(req
);
398 if (!NT_STATUS_IS_OK(status
)) {
399 return smbd_smb2_request_error(req
, status
);
401 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
404 if (!NT_STATUS_IS_OK(session_status
)) {
405 return smbd_smb2_request_error(req
, session_status
);
407 status
= smbd_smb2_request_check_tcon(req
);
408 if (!NT_STATUS_IS_OK(status
)) {
409 return smbd_smb2_request_error(req
, status
);
411 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
414 if (!NT_STATUS_IS_OK(session_status
)) {
415 return smbd_smb2_request_error(req
, session_status
);
417 status
= smbd_smb2_request_check_tcon(req
);
418 if (!NT_STATUS_IS_OK(status
)) {
419 return smbd_smb2_request_error(req
, status
);
421 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
424 if (!NT_STATUS_IS_OK(session_status
)) {
425 return smbd_smb2_request_error(req
, session_status
);
427 status
= smbd_smb2_request_check_tcon(req
);
428 if (!NT_STATUS_IS_OK(status
)) {
429 return smbd_smb2_request_error(req
, status
);
431 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
434 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
436 case SMB2_OP_KEEPALIVE
:
437 return smbd_smb2_request_process_keepalive(req
);
440 if (!NT_STATUS_IS_OK(session_status
)) {
441 return smbd_smb2_request_error(req
, session_status
);
443 status
= smbd_smb2_request_check_tcon(req
);
444 if (!NT_STATUS_IS_OK(status
)) {
445 return smbd_smb2_request_error(req
, status
);
447 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
450 if (!NT_STATUS_IS_OK(session_status
)) {
451 return smbd_smb2_request_error(req
, session_status
);
453 status
= smbd_smb2_request_check_tcon(req
);
454 if (!NT_STATUS_IS_OK(status
)) {
455 return smbd_smb2_request_error(req
, status
);
457 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
459 case SMB2_OP_GETINFO
:
460 if (!NT_STATUS_IS_OK(session_status
)) {
461 return smbd_smb2_request_error(req
, session_status
);
463 status
= smbd_smb2_request_check_tcon(req
);
464 if (!NT_STATUS_IS_OK(status
)) {
465 return smbd_smb2_request_error(req
, status
);
467 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
469 case SMB2_OP_SETINFO
:
470 if (!NT_STATUS_IS_OK(session_status
)) {
471 return smbd_smb2_request_error(req
, session_status
);
473 status
= smbd_smb2_request_check_tcon(req
);
474 if (!NT_STATUS_IS_OK(status
)) {
475 return smbd_smb2_request_error(req
, status
);
477 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
480 if (!NT_STATUS_IS_OK(session_status
)) {
481 return smbd_smb2_request_error(req
, session_status
);
483 status
= smbd_smb2_request_check_tcon(req
);
484 if (!NT_STATUS_IS_OK(status
)) {
485 return smbd_smb2_request_error(req
, status
);
487 return smbd_smb2_request_error(req
, NT_STATUS_NOT_IMPLEMENTED
);
490 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
493 static void smbd_smb2_request_dispatch_compound(struct tevent_req
*subreq
);
494 static void smbd_smb2_request_writev_done(struct tevent_req
*subreq
);
496 static NTSTATUS
smbd_smb2_request_reply(struct smbd_smb2_request
*req
)
498 struct tevent_req
*subreq
;
500 /* TODO: sign the response here */
502 smb2_setup_nbt_length(req
->out
.vector
, req
->out
.vector_count
);
504 if (req
->do_signing
) {
505 int i
= req
->current_idx
;
507 status
= smb2_signing_sign_pdu(req
->session
->session_key
,
508 &req
->out
.vector
[i
], 3);
509 if (!NT_STATUS_IS_OK(status
)) {
514 req
->current_idx
+= 3;
516 if (req
->current_idx
> req
->in
.vector_count
) {
517 struct timeval zero
= timeval_zero();
518 subreq
= tevent_wakeup_send(req
,
519 req
->conn
->smb2
.event_ctx
,
521 if (subreq
== NULL
) {
522 return NT_STATUS_NO_MEMORY
;
524 tevent_req_set_callback(subreq
,
525 smbd_smb2_request_dispatch_compound
,
531 subreq
= tstream_writev_queue_send(req
,
532 req
->conn
->smb2
.event_ctx
,
533 req
->conn
->smb2
.stream
,
534 req
->conn
->smb2
.send_queue
,
536 req
->out
.vector_count
);
537 if (subreq
== NULL
) {
538 return NT_STATUS_NO_MEMORY
;
540 tevent_req_set_callback(subreq
, smbd_smb2_request_writev_done
, req
);
545 static void smbd_smb2_request_dispatch_compound(struct tevent_req
*subreq
)
547 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
548 struct smbd_smb2_request
);
549 struct smbd_server_connection
*conn
= req
->conn
;
552 tevent_wakeup_recv(subreq
);
555 DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n",
556 req
->current_idx
, req
->in
.vector_count
));
558 status
= smbd_smb2_request_dispatch(req
);
559 if (!NT_STATUS_IS_OK(status
)) {
560 smbd_server_connection_terminate(conn
, nt_errstr(status
));
565 static void smbd_smb2_request_writev_done(struct tevent_req
*subreq
)
567 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
568 struct smbd_smb2_request
);
569 struct smbd_server_connection
*conn
= req
->conn
;
572 TALLOC_CTX
*mem_pool
;
574 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
577 NTSTATUS status
= map_nt_error_from_unix(sys_errno
);
578 smbd_server_connection_terminate(conn
, nt_errstr(status
));
582 mem_pool
= req
->mem_pool
;
584 talloc_free(mem_pool
);
587 NTSTATUS
smbd_smb2_request_error_ex(struct smbd_smb2_request
*req
,
593 int i
= req
->current_idx
;
595 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s]%s\n",
596 i
, nt_errstr(status
), info
? " +info" : ""));
598 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
600 SIVAL(outhdr
, SMB2_HDR_STATUS
, NT_STATUS_V(status
));
602 outbody
= outhdr
+ SMB2_HDR_BODY
;
604 req
->out
.vector
[i
+1].iov_base
= (void *)outbody
;
605 req
->out
.vector
[i
+1].iov_len
= 8;
608 SIVAL(outbody
, 0x04, info
->length
);
609 req
->out
.vector
[i
+2].iov_base
= (void *)info
->data
;
610 req
->out
.vector
[i
+2].iov_len
= info
->length
;
612 req
->out
.vector
[i
+2].iov_base
= (void *)(outbody
+ 8);
613 req
->out
.vector
[i
+2].iov_len
= 1;
616 /* the error packet is the last response in the chain */
617 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, 0);
618 req
->out
.vector_count
= req
->current_idx
+ 3;
620 return smbd_smb2_request_reply(req
);
623 NTSTATUS
smbd_smb2_request_error(struct smbd_smb2_request
*req
,
626 return smbd_smb2_request_error_ex(req
, status
, NULL
);
629 NTSTATUS
smbd_smb2_request_done_ex(struct smbd_smb2_request
*req
,
631 DATA_BLOB body
, DATA_BLOB
*dyn
)
635 int i
= req
->current_idx
;
636 uint32_t next_command_ofs
;
638 DEBUG(10,("smbd_smb2_request_done_ex: "
639 "idx[%d] status[%s] body[%u] dyn[%s:%u]\n",
640 i
, nt_errstr(status
), (unsigned int)body
.length
,
642 (unsigned int)(dyn
? dyn
->length
: 0)));
644 if (body
.length
< 2) {
645 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
648 if ((body
.length
% 2) != 0) {
649 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
652 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
653 /* the fallback dynamic buffer */
654 outdyn
= outhdr
+ SMB2_HDR_BODY
+ 8;
656 next_command_ofs
= IVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
);
657 SIVAL(outhdr
, SMB2_HDR_STATUS
, NT_STATUS_V(status
));
659 req
->out
.vector
[i
+1].iov_base
= (void *)body
.data
;
660 req
->out
.vector
[i
+1].iov_len
= body
.length
;
663 if (dyn
->length
> 0) {
664 req
->out
.vector
[i
+2].iov_base
= (void *)dyn
->data
;
665 req
->out
.vector
[i
+2].iov_len
= dyn
->length
;
667 req
->out
.vector
[i
+2].iov_base
= (void *)outdyn
;
668 req
->out
.vector
[i
+2].iov_len
= 1;
671 req
->out
.vector
[i
+2].iov_base
= NULL
;
672 req
->out
.vector
[i
+2].iov_len
= 0;
675 /* see if we need to recalculate the offset to the next response */
676 if (next_command_ofs
> 0) {
677 next_command_ofs
= SMB2_HDR_BODY
;
678 next_command_ofs
+= req
->out
.vector
[i
+1].iov_len
;
679 next_command_ofs
+= req
->out
.vector
[i
+2].iov_len
;
682 /* TODO: we need to add padding ... */
683 if ((next_command_ofs
% 8) != 0) {
684 return smbd_smb2_request_error(req
, NT_STATUS_INTERNAL_ERROR
);
687 /* the error packet is the last response in the chain */
688 SIVAL(outhdr
, SMB2_HDR_NEXT_COMMAND
, next_command_ofs
);
690 return smbd_smb2_request_reply(req
);
693 NTSTATUS
smbd_smb2_request_done(struct smbd_smb2_request
*req
,
694 DATA_BLOB body
, DATA_BLOB
*dyn
)
696 return smbd_smb2_request_done_ex(req
, NT_STATUS_OK
, body
, dyn
);
699 struct smbd_smb2_request_read_state
{
701 bool asked_for_header
;
702 struct smbd_smb2_request
*smb2_req
;
705 static int smbd_smb2_request_next_vector(struct tstream_context
*stream
,
708 struct iovec
**_vector
,
710 static void smbd_smb2_request_read_done(struct tevent_req
*subreq
);
712 static struct tevent_req
*smbd_smb2_request_read_send(TALLOC_CTX
*mem_ctx
,
713 struct tevent_context
*ev
,
714 struct smbd_server_connection
*conn
)
716 struct tevent_req
*req
;
717 struct smbd_smb2_request_read_state
*state
;
718 struct tevent_req
*subreq
;
719 TALLOC_CTX
*mem_pool
;
721 req
= tevent_req_create(mem_ctx
, &state
,
722 struct smbd_smb2_request_read_state
);
727 state
->asked_for_header
= false;
729 mem_pool
= talloc_pool(state
, 8192);
730 if (tevent_req_nomem(mem_pool
, req
)) {
731 return tevent_req_post(req
, ev
);
734 state
->smb2_req
= talloc_zero(mem_pool
, struct smbd_smb2_request
);
735 if (tevent_req_nomem(state
->smb2_req
, req
)) {
736 return tevent_req_post(req
, ev
);
739 state
->smb2_req
->mem_pool
= mem_pool
;
740 state
->smb2_req
->conn
= conn
;
742 subreq
= tstream_readv_pdu_queue_send(state
, ev
, conn
->smb2
.stream
,
743 conn
->smb2
.recv_queue
,
744 smbd_smb2_request_next_vector
,
746 if (tevent_req_nomem(subreq
, req
)) {
747 return tevent_req_post(req
, ev
);
749 tevent_req_set_callback(subreq
, smbd_smb2_request_read_done
, req
);
754 static int smbd_smb2_request_next_vector(struct tstream_context
*stream
,
757 struct iovec
**_vector
,
760 struct smbd_smb2_request_read_state
*state
=
761 talloc_get_type_abort(private_data
,
762 struct smbd_smb2_request_read_state
);
763 struct smbd_smb2_request
*req
= state
->smb2_req
;
764 struct iovec
*vector
;
765 int idx
= req
->in
.vector_count
;
769 if (req
->in
.vector_count
== 0) {
771 * first we need to get the NBT header
773 req
->in
.vector
= talloc_array(req
, struct iovec
,
774 req
->in
.vector_count
+ 1);
775 if (req
->in
.vector
== NULL
) {
778 req
->in
.vector_count
+= 1;
780 req
->in
.vector
[idx
].iov_base
= (void *)req
->in
.nbt_hdr
;
781 req
->in
.vector
[idx
].iov_len
= 4;
783 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
784 if (vector
== NULL
) {
788 vector
[0] = req
->in
.vector
[idx
];
795 if (req
->in
.vector_count
== 1) {
797 * Now we analyze the NBT header
799 state
->missing
= smb2_len(req
->in
.vector
[0].iov_base
);
801 if (state
->missing
== 0) {
802 /* if there're no remaining bytes, we're done */
808 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
810 req
->in
.vector_count
+ 1);
811 if (req
->in
.vector
== NULL
) {
814 req
->in
.vector_count
+= 1;
816 if (CVAL(req
->in
.vector
[0].iov_base
, 0) != 0) {
818 * it's a special NBT message,
819 * so get all remaining bytes
821 len
= state
->missing
;
822 } else if (state
->missing
< (SMB2_HDR_BODY
+ 2)) {
824 * it's an invalid message, just read what we can get
825 * and let the caller handle the error
827 len
= state
->missing
;
830 * We assume it's a SMB2 request,
831 * and we first get the header and the
832 * first 2 bytes (the struct size) of the body
834 len
= SMB2_HDR_BODY
+ 2;
836 state
->asked_for_header
= true;
839 state
->missing
-= len
;
841 buf
= talloc_array(req
->in
.vector
, uint8_t, len
);
846 req
->in
.vector
[idx
].iov_base
= (void *)buf
;
847 req
->in
.vector
[idx
].iov_len
= len
;
849 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
850 if (vector
== NULL
) {
854 vector
[0] = req
->in
.vector
[idx
];
861 if (state
->missing
== 0) {
862 /* if there're no remaining bytes, we're done */
868 if (state
->asked_for_header
) {
871 size_t next_command_ofs
;
876 bool invalid
= false;
878 state
->asked_for_header
= false;
881 * We got the SMB2 header and the first 2 bytes
882 * of the body. We fix the size to just the header
883 * and manually copy the 2 first bytes to the body section
885 req
->in
.vector
[idx
-1].iov_len
= SMB2_HDR_BODY
;
886 hdr
= (const uint8_t *)req
->in
.vector
[idx
-1].iov_base
;
888 /* allocate vectors for body and dynamic areas */
889 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
891 req
->in
.vector_count
+ 2);
892 if (req
->in
.vector
== NULL
) {
895 req
->in
.vector_count
+= 2;
897 full_size
= state
->missing
+ SMB2_HDR_BODY
+ 2;
898 next_command_ofs
= IVAL(hdr
, SMB2_HDR_NEXT_COMMAND
);
899 body_size
= SVAL(hdr
, SMB2_HDR_BODY
);
901 if (next_command_ofs
!= 0) {
902 if (next_command_ofs
< (SMB2_HDR_BODY
+ 2)) {
904 * this is invalid, just return a zero
905 * body and let the caller deal with the error
908 } else if (next_command_ofs
> full_size
) {
910 * this is invalid, just return a zero
911 * body and let the caller deal with the error
915 full_size
= next_command_ofs
;
922 * this is invalid, just return a zero
923 * body and let the caller deal with the error
926 } else if (body_size
> (full_size
- SMB2_HDR_BODY
)) {
928 * this is invalid, just return a zero
929 * body and let the caller deal with the error
936 /* the caller should check this */
940 if ((body_size
% 2) != 0) {
944 dyn_size
= full_size
- (SMB2_HDR_BODY
+ body_size
);
946 state
->missing
-= (body_size
- 2) + dyn_size
;
948 body
= talloc_array(req
->in
.vector
, uint8_t, body_size
);
953 dyn
= talloc_array(req
->in
.vector
, uint8_t, dyn_size
);
958 req
->in
.vector
[idx
].iov_base
= (void *)body
;
959 req
->in
.vector
[idx
].iov_len
= body_size
;
960 req
->in
.vector
[idx
+1].iov_base
= (void *)dyn
;
961 req
->in
.vector
[idx
+1].iov_len
= dyn_size
;
963 vector
= talloc_array(mem_ctx
, struct iovec
, 2);
964 if (vector
== NULL
) {
969 * the first 2 bytes of the body were already fetched
970 * together with the header
972 memcpy(body
, hdr
+ SMB2_HDR_BODY
, 2);
973 vector
[0].iov_base
= body
+ 2;
974 vector
[0].iov_len
= req
->in
.vector
[idx
].iov_len
- 2;
976 vector
[1] = req
->in
.vector
[idx
+1];
984 * when we endup here, we're looking for a new SMB2 request
985 * next. And we ask for its header and the first 2 bytes of
986 * the body (like we did for the first SMB2 request).
989 req
->in
.vector
= talloc_realloc(req
, req
->in
.vector
,
991 req
->in
.vector_count
+ 1);
992 if (req
->in
.vector
== NULL
) {
995 req
->in
.vector_count
+= 1;
998 * We assume it's a SMB2 request,
999 * and we first get the header and the
1000 * first 2 bytes (the struct size) of the body
1002 len
= SMB2_HDR_BODY
+ 2;
1004 if (len
> state
->missing
) {
1005 /* let the caller handle the error */
1006 len
= state
->missing
;
1009 state
->missing
-= len
;
1010 state
->asked_for_header
= true;
1012 buf
= talloc_array(req
->in
.vector
, uint8_t, len
);
1017 req
->in
.vector
[idx
].iov_base
= (void *)buf
;
1018 req
->in
.vector
[idx
].iov_len
= len
;
1020 vector
= talloc_array(mem_ctx
, struct iovec
, 1);
1021 if (vector
== NULL
) {
1025 vector
[0] = req
->in
.vector
[idx
];
1032 static void smbd_smb2_request_read_done(struct tevent_req
*subreq
)
1034 struct tevent_req
*req
=
1035 tevent_req_callback_data(subreq
,
1041 ret
= tstream_readv_pdu_queue_recv(subreq
, &sys_errno
);
1043 status
= map_nt_error_from_unix(sys_errno
);
1044 tevent_req_nterror(req
, status
);
1048 tevent_req_done(req
);
1051 static NTSTATUS
smbd_smb2_request_read_recv(struct tevent_req
*req
,
1052 TALLOC_CTX
*mem_ctx
,
1053 struct smbd_smb2_request
**_smb2_req
)
1055 struct smbd_smb2_request_read_state
*state
=
1056 tevent_req_data(req
,
1057 struct smbd_smb2_request_read_state
);
1060 if (tevent_req_is_nterror(req
, &status
)) {
1061 tevent_req_received(req
);
1065 talloc_steal(mem_ctx
, state
->smb2_req
->mem_pool
);
1066 *_smb2_req
= state
->smb2_req
;
1067 tevent_req_received(req
);
1068 return NT_STATUS_OK
;
1071 static void smbd_smb2_request_incoming(struct tevent_req
*subreq
);
1073 void smbd_smb2_first_negprot(struct smbd_server_connection
*conn
,
1074 const uint8_t *inbuf
, size_t size
)
1077 struct smbd_smb2_request
*req
;
1078 struct tevent_req
*subreq
;
1080 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
1081 (unsigned int)size
));
1083 status
= smbd_initialize_smb2(conn
);
1084 if (!NT_STATUS_IS_OK(status
)) {
1085 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1089 status
= smbd_smb2_request_create(conn
, inbuf
, size
, &req
);
1090 if (!NT_STATUS_IS_OK(status
)) {
1091 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1095 status
= smbd_smb2_request_setup_out(req
);
1096 if (!NT_STATUS_IS_OK(status
)) {
1097 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1101 status
= smbd_smb2_request_dispatch(req
);
1102 if (!NT_STATUS_IS_OK(status
)) {
1103 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1107 /* ask for the next request */
1108 subreq
= smbd_smb2_request_read_send(conn
,conn
->smb2
.event_ctx
, conn
);
1109 if (subreq
== NULL
) {
1110 smbd_server_connection_terminate(conn
, "no memory for reading");
1113 tevent_req_set_callback(subreq
, smbd_smb2_request_incoming
, conn
);
1116 static void smbd_smb2_request_incoming(struct tevent_req
*subreq
)
1118 struct smbd_server_connection
*conn
= tevent_req_callback_data(subreq
,
1119 struct smbd_server_connection
);
1121 struct smbd_smb2_request
*req
;
1123 status
= smbd_smb2_request_read_recv(subreq
, conn
, &req
);
1124 TALLOC_FREE(subreq
);
1125 if (!NT_STATUS_IS_OK(status
)) {
1126 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1130 /* TODO: validate the incoming request */
1131 req
->current_idx
= 1;
1133 DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
1134 req
->current_idx
, req
->in
.vector_count
));
1136 status
= smbd_smb2_request_setup_out(req
);
1137 if (!NT_STATUS_IS_OK(status
)) {
1138 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1142 status
= smbd_smb2_request_dispatch(req
);
1143 if (!NT_STATUS_IS_OK(status
)) {
1144 smbd_server_connection_terminate(conn
, nt_errstr(status
));
1148 /* ask for the next request (this constructs the main loop) */
1149 subreq
= smbd_smb2_request_read_send(conn
,conn
->smb2
.event_ctx
, conn
);
1150 if (subreq
== NULL
) {
1151 smbd_server_connection_terminate(conn
, "no memory for reading");
1154 tevent_req_set_callback(subreq
, smbd_smb2_request_incoming
, conn
);