Line data Source code
1 : /*
2 : Unix SMB2 implementation.
3 :
4 : Copyright (C) Andrew Tridgell 2005
5 : Copyright (C) Stefan Metzmacher 2005
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/time.h"
23 : #include "libcli/smb2/smb2.h"
24 : #include "libcli/smb2/smb2_calls.h"
25 : #include "smb_server/smb_server.h"
26 : #include "smb_server/smb2/smb2_server.h"
27 : #include "samba/service_stream.h"
28 : #include "lib/stream/packet.h"
29 : #include "ntvfs/ntvfs.h"
30 : #include "param/param.h"
31 : #include "auth/auth.h"
32 : #include "lib/util/idtree.h"
33 :
34 : /* fill in the bufinfo */
35 414780 : void smb2srv_setup_bufinfo(struct smb2srv_request *req)
36 : {
37 414780 : req->in.bufinfo.mem_ctx = req;
38 414780 : req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
39 414780 : req->in.bufinfo.align_base = req->in.buffer;
40 414780 : if (req->in.dynamic) {
41 269063 : req->in.bufinfo.data = req->in.dynamic;
42 269063 : req->in.bufinfo.data_size = req->in.body_size - req->in.body_fixed;
43 : } else {
44 145717 : req->in.bufinfo.data = NULL;
45 145717 : req->in.bufinfo.data_size = 0;
46 : }
47 414780 : }
48 :
49 413563 : static int smb2srv_request_destructor(struct smb2srv_request *req)
50 : {
51 413563 : DLIST_REMOVE(req->smb_conn->requests2.list, req);
52 413563 : if (req->pending_id) {
53 52064 : idr_remove(req->smb_conn->requests2.idtree_req, req->pending_id);
54 : }
55 413563 : return 0;
56 : }
57 :
58 52064 : static int smb2srv_request_deny_destructor(struct smb2srv_request *req)
59 : {
60 52064 : return -1;
61 : }
62 :
63 413563 : struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
64 : {
65 0 : struct smb2srv_request *req;
66 :
67 413563 : req = talloc_zero(smb_conn, struct smb2srv_request);
68 413563 : if (!req) return NULL;
69 :
70 413563 : req->smb_conn = smb_conn;
71 :
72 413563 : req->chained_session_id = UINT64_MAX;
73 413563 : req->chained_tree_id = UINT32_MAX;
74 :
75 413563 : talloc_set_destructor(req, smb2srv_request_destructor);
76 :
77 413563 : return req;
78 : }
79 :
80 466842 : NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_size,
81 : bool body_dynamic_present, uint32_t body_dynamic_size)
82 : {
83 466842 : uint32_t flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
84 466842 : uint32_t pid = IVAL(req->in.hdr, SMB2_HDR_PID);
85 466842 : uint32_t tid = IVAL(req->in.hdr, SMB2_HDR_TID);
86 466842 : uint16_t credits = SVAL(req->in.hdr, SMB2_HDR_CREDIT);
87 :
88 466842 : if (credits == 0) {
89 2148 : credits = 1;
90 : }
91 :
92 466842 : flags |= SMB2_HDR_FLAG_REDIRECT;
93 :
94 466842 : if (req->pending_id) {
95 104128 : flags |= SMB2_HDR_FLAG_ASYNC;
96 104128 : pid = req->pending_id;
97 104128 : tid = 0;
98 104128 : credits = 0;
99 : }
100 :
101 466842 : if (body_dynamic_present) {
102 321320 : if (body_dynamic_size == 0) {
103 314785 : body_dynamic_size = 1;
104 : }
105 : } else {
106 145522 : body_dynamic_size = 0;
107 : }
108 :
109 466842 : req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
110 :
111 466842 : req->out.allocated = req->out.size + body_dynamic_size;
112 466842 : req->out.buffer = talloc_array(req, uint8_t,
113 : req->out.allocated);
114 466842 : NT_STATUS_HAVE_NO_MEMORY(req->out.buffer);
115 :
116 466842 : req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
117 466842 : req->out.body = req->out.hdr + SMB2_HDR_BODY;
118 466842 : req->out.body_fixed = body_fixed_size;
119 466842 : req->out.body_size = body_fixed_size;
120 466842 : req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
121 :
122 466842 : SIVAL(req->out.hdr, 0, SMB2_MAGIC);
123 466842 : SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
124 466842 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE,
125 : SVAL(req->in.hdr, SMB2_HDR_CREDIT_CHARGE));
126 466842 : SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status));
127 466842 : SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE));
128 466842 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT, credits);
129 466842 : SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags);
130 466842 : SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
131 466842 : SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, req->seqnum);
132 466842 : SIVAL(req->out.hdr, SMB2_HDR_PID, pid);
133 466842 : SIVAL(req->out.hdr, SMB2_HDR_TID, tid);
134 466842 : SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, BVAL(req->in.hdr, SMB2_HDR_SESSION_ID));
135 466842 : memcpy(req->out.hdr+SMB2_HDR_SIGNATURE,
136 466842 : req->in.hdr+SMB2_HDR_SIGNATURE, 16);
137 :
138 : /* set the length of the fixed body part and +1 if there's a dynamic part also */
139 466842 : SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
140 :
141 : /*
142 : * if we have a dynamic part, make sure the first byte
143 : * which is always be part of the packet is initialized
144 : */
145 466842 : if (body_dynamic_size) {
146 321320 : req->out.size += 1;
147 321320 : SCVAL(req->out.dynamic, 0, 0);
148 : }
149 :
150 466842 : return NT_STATUS_OK;
151 : }
152 :
153 : static NTSTATUS smb2srv_reply(struct smb2srv_request *req);
154 :
155 0 : static void smb2srv_chain_reply(struct smb2srv_request *p_req)
156 : {
157 0 : NTSTATUS status;
158 0 : struct smbsrv_connection *smb_conn = p_req->smb_conn;
159 0 : struct smb2srv_request *req;
160 0 : uint32_t chain_offset;
161 0 : uint32_t protocol_version;
162 0 : uint16_t buffer_code;
163 0 : uint32_t dynamic_size;
164 0 : uint32_t flags;
165 0 : uint32_t last_hdr_offset;
166 :
167 0 : last_hdr_offset = p_req->in.hdr - p_req->in.buffer;
168 :
169 0 : chain_offset = p_req->chain_offset;
170 0 : p_req->chain_offset = 0;
171 :
172 0 : if (p_req->in.size < (last_hdr_offset + chain_offset + SMB2_MIN_SIZE_NO_BODY)) {
173 0 : DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X from last hdr 0x%X\n",
174 : chain_offset, last_hdr_offset));
175 0 : smbsrv_terminate_connection(smb_conn, "Invalid SMB2 chained packet");
176 0 : return;
177 : }
178 :
179 0 : protocol_version = IVAL(p_req->in.buffer, last_hdr_offset + chain_offset);
180 0 : if (protocol_version != SMB2_MAGIC) {
181 0 : DEBUG(2,("Invalid SMB chained packet: protocol prefix: 0x%08X\n",
182 : protocol_version));
183 0 : smbsrv_terminate_connection(smb_conn, "NON-SMB2 chained packet");
184 0 : return;
185 : }
186 :
187 0 : req = smb2srv_init_request(smb_conn);
188 0 : if (!req) {
189 0 : smbsrv_terminate_connection(smb_conn, "SMB2 chained packet - no memory");
190 0 : return;
191 : }
192 :
193 0 : talloc_steal(req, p_req);
194 :
195 0 : req->in.buffer = talloc_steal(req, p_req->in.buffer);
196 0 : req->in.size = p_req->in.size;
197 0 : req->request_time = p_req->request_time;
198 0 : req->in.allocated = req->in.size;
199 :
200 0 : req->in.hdr = req->in.buffer+ last_hdr_offset + chain_offset;
201 0 : req->in.body = req->in.hdr + SMB2_HDR_BODY;
202 0 : req->in.body_size = req->in.size - (last_hdr_offset+ chain_offset + SMB2_HDR_BODY);
203 0 : req->in.dynamic = NULL;
204 :
205 0 : req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
206 :
207 0 : if (req->in.body_size < 2) {
208 : /* error handling for this is different for negprot to
209 : other packet types */
210 0 : uint16_t opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
211 0 : if (opcode == SMB2_OP_NEGPROT) {
212 0 : smbsrv_terminate_connection(smb_conn, "Bad body size in SMB2 negprot");
213 0 : return;
214 : } else {
215 0 : smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
216 0 : return;
217 : }
218 : }
219 :
220 0 : buffer_code = SVAL(req->in.body, 0);
221 0 : req->in.body_fixed = (buffer_code & ~1);
222 0 : dynamic_size = req->in.body_size - req->in.body_fixed;
223 :
224 0 : if (dynamic_size != 0 && (buffer_code & 1)) {
225 0 : req->in.dynamic = req->in.body + req->in.body_fixed;
226 0 : if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
227 0 : DEBUG(1,("SMB2 chained request invalid dynamic size 0x%x\n",
228 : dynamic_size));
229 0 : smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
230 0 : return;
231 : }
232 : }
233 :
234 0 : smb2srv_setup_bufinfo(req);
235 :
236 0 : flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
237 0 : if (flags & SMB2_HDR_FLAG_CHAINED) {
238 0 : if (p_req->chained_file_handle) {
239 0 : memcpy(req->_chained_file_handle,
240 0 : p_req->_chained_file_handle,
241 : sizeof(req->_chained_file_handle));
242 0 : req->chained_file_handle = req->_chained_file_handle;
243 : }
244 0 : req->chained_session_id = p_req->chained_session_id;
245 0 : req->chained_tree_id = p_req->chained_tree_id;
246 0 : req->chain_status = p_req->chain_status;
247 : }
248 :
249 : /*
250 : * TODO: - make sure the length field is 64
251 : * - make sure it's a request
252 : */
253 :
254 0 : status = smb2srv_reply(req);
255 0 : if (!NT_STATUS_IS_OK(status)) {
256 0 : smbsrv_terminate_connection(smb_conn, nt_errstr(status));
257 0 : return;
258 : }
259 : }
260 :
261 466842 : void smb2srv_send_reply(struct smb2srv_request *req)
262 : {
263 0 : DATA_BLOB blob;
264 0 : NTSTATUS status;
265 :
266 466842 : if (req->smb_conn->connection->event.fde == NULL) {
267 : /* the socket has been destroyed - no point trying to send a reply! */
268 0 : talloc_free(req);
269 0 : return;
270 : }
271 :
272 466842 : if (req->out.size > NBT_HDR_SIZE) {
273 466842 : _smb_setlen_tcp(req->out.buffer, req->out.size - NBT_HDR_SIZE);
274 : }
275 :
276 : /* if signing is active on the session then sign the packet */
277 466842 : if (req->is_signed) {
278 411669 : status = smb2_sign_message(&req->out,
279 411669 : req->session->session_info->session_key);
280 411669 : if (!NT_STATUS_IS_OK(status)) {
281 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
282 0 : return;
283 : }
284 : }
285 :
286 :
287 466842 : blob = data_blob_const(req->out.buffer, req->out.size);
288 466842 : status = packet_send(req->smb_conn->packet, blob);
289 466842 : if (!NT_STATUS_IS_OK(status)) {
290 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
291 0 : return;
292 : }
293 466842 : if (req->chain_offset) {
294 0 : smb2srv_chain_reply(req);
295 0 : return;
296 : }
297 466842 : talloc_free(req);
298 : }
299 :
300 70627 : void smb2srv_send_error(struct smb2srv_request *req, NTSTATUS error)
301 : {
302 0 : NTSTATUS status;
303 :
304 70627 : if (req->smb_conn->connection->event.fde == NULL) {
305 : /* the socket has been destroyed - no point trying to send an error! */
306 0 : talloc_free(req);
307 0 : return;
308 : }
309 :
310 70627 : status = smb2srv_setup_reply(req, 8, true, 0);
311 70627 : if (!NT_STATUS_IS_OK(status)) {
312 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
313 0 : talloc_free(req);
314 0 : return;
315 : }
316 :
317 70627 : SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(error));
318 :
319 70627 : SSVAL(req->out.body, 0x02, 0);
320 70627 : SIVAL(req->out.body, 0x04, 0);
321 :
322 70627 : req->chain_status = NT_STATUS_INVALID_PARAMETER;
323 :
324 70627 : smb2srv_send_reply(req);
325 : }
326 :
327 413510 : static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
328 : {
329 0 : uint16_t opcode;
330 0 : uint32_t tid;
331 0 : uint64_t uid;
332 0 : uint32_t flags;
333 :
334 413510 : if (SVAL(req->in.hdr, SMB2_HDR_LENGTH) != SMB2_HDR_BODY) {
335 0 : smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 header length");
336 0 : return NT_STATUS_INVALID_PARAMETER;
337 : }
338 413510 : opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
339 413510 : req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND);
340 413510 : req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
341 413510 : tid = IVAL(req->in.hdr, SMB2_HDR_TID);
342 413510 : uid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID);
343 413510 : flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
344 :
345 413510 : if (opcode != SMB2_OP_CANCEL &&
346 413508 : req->smb_conn->highest_smb2_seqnum != 0 &&
347 411505 : req->seqnum <= req->smb_conn->highest_smb2_seqnum) {
348 0 : smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 sequence number");
349 0 : return NT_STATUS_INVALID_PARAMETER;
350 : }
351 413510 : if (opcode != SMB2_OP_CANCEL) {
352 413508 : req->smb_conn->highest_smb2_seqnum = req->seqnum;
353 : }
354 :
355 413510 : if (flags & SMB2_HDR_FLAG_CHAINED) {
356 0 : uid = req->chained_session_id;
357 0 : tid = req->chained_tree_id;
358 : }
359 :
360 413510 : req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
361 413510 : req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
362 :
363 413510 : req->chained_session_id = uid;
364 413510 : req->chained_tree_id = tid;
365 :
366 413510 : errno = 0;
367 :
368 : /* supporting signing is mandatory in SMB2, and is per-packet. So we
369 : should check the signature on any incoming packet that is signed, and
370 : should give a signed reply to any signed request */
371 413510 : if (flags & SMB2_HDR_FLAG_SIGNED) {
372 0 : NTSTATUS status;
373 :
374 410121 : if (!req->session) goto nosession;
375 :
376 410115 : req->is_signed = true;
377 410115 : status = smb2_check_signature(&req->in,
378 410115 : req->session->session_info->session_key);
379 410115 : if (!NT_STATUS_IS_OK(status)) {
380 0 : smb2srv_send_error(req, status);
381 0 : return NT_STATUS_OK;
382 : }
383 3389 : } else if (req->session && req->session->smb2_signing.active) {
384 : /* we require signing and this request was not signed */
385 0 : smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED);
386 0 : return NT_STATUS_OK;
387 : }
388 :
389 413504 : if (!NT_STATUS_IS_OK(req->chain_status)) {
390 0 : smb2srv_send_error(req, req->chain_status);
391 0 : return NT_STATUS_OK;
392 : }
393 :
394 413504 : switch (opcode) {
395 394 : case SMB2_OP_NEGPROT:
396 394 : smb2srv_negprot_recv(req);
397 413491 : return NT_STATUS_OK;
398 2692 : case SMB2_OP_SESSSETUP:
399 2692 : smb2srv_sesssetup_recv(req);
400 2692 : return NT_STATUS_OK;
401 5 : case SMB2_OP_LOGOFF:
402 6 : if (!req->session) goto nosession;
403 4 : smb2srv_logoff_recv(req);
404 4 : return NT_STATUS_OK;
405 1606 : case SMB2_OP_TCON:
406 1606 : if (!req->session) goto nosession;
407 1606 : smb2srv_tcon_recv(req);
408 1606 : return NT_STATUS_OK;
409 451 : case SMB2_OP_TDIS:
410 451 : if (!req->session) goto nosession;
411 456 : if (!req->tcon) goto notcon;
412 445 : smb2srv_tdis_recv(req);
413 445 : return NT_STATUS_OK;
414 209898 : case SMB2_OP_CREATE:
415 209898 : if (!req->session) goto nosession;
416 209898 : if (!req->tcon) goto notcon;
417 209896 : smb2srv_create_recv(req);
418 209896 : return NT_STATUS_OK;
419 143160 : case SMB2_OP_CLOSE:
420 143160 : if (!req->session) goto nosession;
421 143160 : if (!req->tcon) goto notcon;
422 143158 : smb2srv_close_recv(req);
423 143158 : return NT_STATUS_OK;
424 3 : case SMB2_OP_FLUSH:
425 3 : if (!req->session) goto nosession;
426 3 : if (!req->tcon) goto notcon;
427 3 : smb2srv_flush_recv(req);
428 3 : return NT_STATUS_OK;
429 1617 : case SMB2_OP_READ:
430 1617 : if (!req->session) goto nosession;
431 1617 : if (!req->tcon) goto notcon;
432 1617 : smb2srv_read_recv(req);
433 1617 : return NT_STATUS_OK;
434 1823 : case SMB2_OP_WRITE:
435 1823 : if (!req->session) goto nosession;
436 1823 : if (!req->tcon) goto notcon;
437 1823 : smb2srv_write_recv(req);
438 1823 : return NT_STATUS_OK;
439 385 : case SMB2_OP_LOCK:
440 385 : if (!req->session) goto nosession;
441 385 : if (!req->tcon) goto notcon;
442 384 : smb2srv_lock_recv(req);
443 384 : return NT_STATUS_OK;
444 49080 : case SMB2_OP_IOCTL:
445 49080 : if (!req->session) goto nosession;
446 49079 : if (!req->tcon) goto notcon;
447 49079 : smb2srv_ioctl_recv(req);
448 49079 : return NT_STATUS_OK;
449 2 : case SMB2_OP_CANCEL:
450 2 : smb2srv_cancel_recv(req);
451 2 : return NT_STATUS_OK;
452 1 : case SMB2_OP_KEEPALIVE:
453 1 : smb2srv_keepalive_recv(req);
454 1 : return NT_STATUS_OK;
455 906 : case SMB2_OP_QUERY_DIRECTORY:
456 906 : if (!req->session) goto nosession;
457 906 : if (!req->tcon) goto notcon;
458 906 : smb2srv_find_recv(req);
459 906 : return NT_STATUS_OK;
460 0 : case SMB2_OP_NOTIFY:
461 0 : if (!req->session) goto nosession;
462 0 : if (!req->tcon) goto notcon;
463 0 : smb2srv_notify_recv(req);
464 0 : return NT_STATUS_OK;
465 981 : case SMB2_OP_GETINFO:
466 981 : if (!req->session) goto nosession;
467 981 : if (!req->tcon) goto notcon;
468 981 : smb2srv_getinfo_recv(req);
469 981 : return NT_STATUS_OK;
470 458 : case SMB2_OP_SETINFO:
471 458 : if (!req->session) goto nosession;
472 458 : if (!req->tcon) goto notcon;
473 458 : smb2srv_setinfo_recv(req);
474 458 : return NT_STATUS_OK;
475 42 : case SMB2_OP_BREAK:
476 42 : if (!req->session) goto nosession;
477 42 : if (!req->tcon) goto notcon;
478 42 : smb2srv_break_recv(req);
479 42 : return NT_STATUS_OK;
480 : }
481 :
482 0 : DEBUG(1,("Invalid SMB2 opcode: 0x%04X\n", opcode));
483 0 : smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 opcode");
484 0 : return NT_STATUS_OK;
485 :
486 8 : nosession:
487 8 : smb2srv_send_error(req, NT_STATUS_USER_SESSION_DELETED);
488 8 : return NT_STATUS_OK;
489 11 : notcon:
490 11 : smb2srv_send_error(req, NT_STATUS_NETWORK_NAME_DELETED);
491 11 : return NT_STATUS_OK;
492 : }
493 :
494 413510 : NTSTATUS smbsrv_recv_smb2_request(void *private_data, DATA_BLOB blob)
495 : {
496 413510 : struct smbsrv_connection *smb_conn = talloc_get_type(private_data, struct smbsrv_connection);
497 0 : struct smb2srv_request *req;
498 413510 : struct timeval cur_time = timeval_current();
499 0 : uint32_t protocol_version;
500 0 : uint16_t buffer_code;
501 0 : uint32_t dynamic_size;
502 0 : uint32_t flags;
503 :
504 413510 : smb_conn->statistics.last_request_time = cur_time;
505 :
506 : /* see if its a special NBT packet */
507 413510 : if (CVAL(blob.data,0) != 0) {
508 0 : DEBUG(2,("Special NBT packet on SMB2 connection\n"));
509 0 : smbsrv_terminate_connection(smb_conn, "Special NBT packet on SMB2 connection");
510 0 : return NT_STATUS_OK;
511 : }
512 :
513 413510 : if (blob.length < (NBT_HDR_SIZE + SMB2_MIN_SIZE_NO_BODY)) {
514 0 : DEBUG(2,("Invalid SMB2 packet length count %ld\n", (long)blob.length));
515 0 : smbsrv_terminate_connection(smb_conn, "Invalid SMB2 packet");
516 0 : return NT_STATUS_OK;
517 : }
518 :
519 413510 : protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
520 413510 : if (protocol_version != SMB2_MAGIC) {
521 0 : DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n",
522 : protocol_version));
523 0 : smbsrv_terminate_connection(smb_conn, "NON-SMB2 packet");
524 0 : return NT_STATUS_OK;
525 : }
526 :
527 413510 : req = smb2srv_init_request(smb_conn);
528 413510 : NT_STATUS_HAVE_NO_MEMORY(req);
529 :
530 413510 : req->in.buffer = talloc_steal(req, blob.data);
531 413510 : req->in.size = blob.length;
532 413510 : req->request_time = cur_time;
533 413510 : req->in.allocated = req->in.size;
534 :
535 413510 : req->in.hdr = req->in.buffer+ NBT_HDR_SIZE;
536 413510 : req->in.body = req->in.hdr + SMB2_HDR_BODY;
537 413510 : req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE);
538 413510 : req->in.dynamic = NULL;
539 :
540 413510 : req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
541 :
542 413510 : if (req->in.body_size < 2) {
543 : /* error handling for this is different for negprot to
544 : other packet types */
545 0 : uint16_t opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
546 0 : if (opcode == SMB2_OP_NEGPROT) {
547 0 : smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
548 0 : return NT_STATUS_OK;
549 : } else {
550 0 : smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
551 0 : return NT_STATUS_OK;
552 : }
553 : }
554 :
555 413510 : buffer_code = SVAL(req->in.body, 0);
556 413510 : req->in.body_fixed = (buffer_code & ~1);
557 413510 : dynamic_size = req->in.body_size - req->in.body_fixed;
558 :
559 413510 : if (dynamic_size != 0 && (buffer_code & 1)) {
560 269063 : req->in.dynamic = req->in.body + req->in.body_fixed;
561 269063 : if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
562 0 : DEBUG(1,("SMB2 request invalid dynamic size 0x%x\n",
563 : dynamic_size));
564 0 : smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
565 0 : return NT_STATUS_OK;
566 : }
567 : }
568 :
569 413510 : smb2srv_setup_bufinfo(req);
570 :
571 : /*
572 : * TODO: - make sure the length field is 64
573 : * - make sure it's a request
574 : */
575 :
576 413510 : flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
577 : /* the first request should never have the related flag set */
578 413510 : if (flags & SMB2_HDR_FLAG_CHAINED) {
579 0 : req->chain_status = NT_STATUS_INVALID_PARAMETER;
580 : }
581 :
582 413510 : return smb2srv_reply(req);
583 : }
584 :
585 1611 : static NTSTATUS smb2srv_init_pending(struct smbsrv_connection *smb_conn)
586 : {
587 1611 : smb_conn->requests2.idtree_req = idr_init(smb_conn);
588 1611 : NT_STATUS_HAVE_NO_MEMORY(smb_conn->requests2.idtree_req);
589 1611 : smb_conn->requests2.idtree_limit = 0x00FFFFFF & (UINT32_MAX - 1);
590 1611 : smb_conn->requests2.list = NULL;
591 :
592 1611 : return NT_STATUS_OK;
593 : }
594 :
595 52064 : NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req)
596 : {
597 0 : NTSTATUS status;
598 52064 : bool signing_used = false;
599 0 : int id;
600 52064 : uint16_t credits = SVAL(req->in.hdr, SMB2_HDR_CREDIT);
601 :
602 52064 : if (credits == 0) {
603 385 : credits = 1;
604 : }
605 :
606 52064 : if (req->pending_id) {
607 0 : return NT_STATUS_INTERNAL_ERROR;
608 : }
609 :
610 52064 : if (req->smb_conn->connection->event.fde == NULL) {
611 : /* the socket has been destroyed - no point trying to send an error! */
612 0 : return NT_STATUS_REMOTE_DISCONNECT;
613 : }
614 :
615 52064 : id = idr_get_new_above(req->smb_conn->requests2.idtree_req, req,
616 52064 : 1, req->smb_conn->requests2.idtree_limit);
617 52064 : if (id == -1) {
618 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
619 : }
620 :
621 52064 : DLIST_ADD_END(req->smb_conn->requests2.list, req);
622 52064 : req->pending_id = id;
623 :
624 52064 : talloc_set_destructor(req, smb2srv_request_deny_destructor);
625 :
626 52064 : status = smb2srv_setup_reply(req, 8, true, 0);
627 52064 : if (!NT_STATUS_IS_OK(status)) {
628 0 : return status;
629 : }
630 :
631 52064 : SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(NT_STATUS_PENDING));
632 52064 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT, credits);
633 :
634 52064 : SSVAL(req->out.body, 0x02, 0);
635 52064 : SIVAL(req->out.body, 0x04, 0);
636 :
637 : /* if the real reply will be signed set the signed flags, but don't sign */
638 52064 : if (req->is_signed) {
639 51877 : SIVAL(req->out.hdr, SMB2_HDR_FLAGS, IVAL(req->out.hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
640 51877 : signing_used = req->is_signed;
641 51877 : req->is_signed = false;
642 : }
643 :
644 52064 : smb2srv_send_reply(req);
645 :
646 52064 : req->is_signed = signing_used;
647 :
648 52064 : talloc_set_destructor(req, smb2srv_request_destructor);
649 52064 : return NT_STATUS_OK;
650 : }
651 :
652 2 : void smb2srv_cancel_recv(struct smb2srv_request *req)
653 : {
654 0 : uint32_t pending_id;
655 0 : uint32_t flags;
656 0 : void *p;
657 0 : struct smb2srv_request *r;
658 :
659 2 : if (!req->session) goto done;
660 :
661 2 : flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
662 2 : pending_id = IVAL(req->in.hdr, SMB2_HDR_PID);
663 :
664 2 : if (!(flags & SMB2_HDR_FLAG_ASYNC)) {
665 : /* TODO: what to do here? */
666 0 : goto done;
667 : }
668 :
669 2 : p = idr_find(req->smb_conn->requests2.idtree_req, pending_id);
670 2 : if (!p) goto done;
671 :
672 2 : r = talloc_get_type(p, struct smb2srv_request);
673 2 : if (!r) goto done;
674 :
675 2 : if (!r->ntvfs) goto done;
676 :
677 2 : ntvfs_cancel(r->ntvfs);
678 :
679 2 : done:
680 : /* we never generate a reply for a SMB2 Cancel */
681 2 : talloc_free(req);
682 2 : }
683 :
684 : /*
685 : * init the SMB2 protocol related stuff
686 : */
687 1611 : NTSTATUS smbsrv_init_smb2_connection(struct smbsrv_connection *smb_conn)
688 : {
689 0 : NTSTATUS status;
690 :
691 : /* now initialise a few default values associated with this smb socket */
692 1611 : smb_conn->negotiate.max_send = 0xFFFF;
693 :
694 : /* this is the size that w2k uses, and it appears to be important for
695 : good performance */
696 1611 : smb_conn->negotiate.max_recv = lpcfg_max_xmit(smb_conn->lp_ctx);
697 :
698 1611 : smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
699 :
700 1611 : smb_conn->config.nt_status_support = true;
701 :
702 1611 : status = smbsrv_init_sessions(smb_conn, UINT64_MAX);
703 1611 : NT_STATUS_NOT_OK_RETURN(status);
704 :
705 1611 : status = smb2srv_init_pending(smb_conn);
706 1611 : NT_STATUS_NOT_OK_RETURN(status);
707 :
708 1611 : return NT_STATUS_OK;
709 :
710 : }
|