r25551: Convert to standard bool type.
[Samba.git] / source / smb_server / smb2 / receive.c
bloba440c33dc0a02006f065c41677ee0e5547659b7d
1 /*
2 Unix SMB2 implementation.
4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Stefan Metzmacher 2005
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/>.
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/service_smb_proto.h"
27 #include "smb_server/smb2/smb2_server.h"
28 #include "smbd/service_stream.h"
29 #include "lib/stream/packet.h"
30 #include "ntvfs/ntvfs.h"
31 #include "param/param.h"
33 static int smb2srv_request_destructor(struct smb2srv_request *req)
35 DLIST_REMOVE(req->smb_conn->requests2.list, req);
36 if (req->pending_id) {
37 idr_remove(req->smb_conn->requests2.idtree_req, req->pending_id);
39 return 0;
42 static int smb2srv_request_deny_destructor(struct smb2srv_request *req)
44 return -1;
47 struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
49 struct smb2srv_request *req;
51 req = talloc_zero(smb_conn, struct smb2srv_request);
52 if (!req) return NULL;
54 req->smb_conn = smb_conn;
56 talloc_set_destructor(req, smb2srv_request_destructor);
58 return req;
61 NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_size,
62 bool body_dynamic_present, uint32_t body_dynamic_size)
64 uint32_t flags = 0x00000001;
65 uint32_t pid = IVAL(req->in.hdr, SMB2_HDR_PID);
66 uint32_t tid = IVAL(req->in.hdr, SMB2_HDR_TID);
68 if (req->pending_id) {
69 flags |= 0x00000002;
70 pid = req->pending_id;
71 tid = 0;
74 if (body_dynamic_present) {
75 if (body_dynamic_size == 0) {
76 body_dynamic_size = 1;
78 } else {
79 body_dynamic_size = 0;
82 req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
84 req->out.allocated = req->out.size + body_dynamic_size;
85 req->out.buffer = talloc_array(req, uint8_t,
86 req->out.allocated);
87 NT_STATUS_HAVE_NO_MEMORY(req->out.buffer);
89 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
90 req->out.body = req->out.hdr + SMB2_HDR_BODY;
91 req->out.body_fixed = body_fixed_size;
92 req->out.body_size = body_fixed_size;
93 req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
95 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
96 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
97 SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
98 SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status));
99 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE));
100 SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0x0001);
101 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags);
102 SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET, 0);
103 SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
104 SIVAL(req->out.hdr, SMB2_HDR_PID, pid);
105 SIVAL(req->out.hdr, SMB2_HDR_TID, tid);
106 SBVAL(req->out.hdr, SMB2_HDR_UID, BVAL(req->in.hdr, SMB2_HDR_UID));
107 memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
109 /* set the length of the fixed body part and +1 if there's a dynamic part also */
110 SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
113 * if we have a dynamic part, make sure the first byte
114 * which is always be part of the packet is initialized
116 if (body_dynamic_size) {
117 req->out.size += 1;
118 SCVAL(req->out.dynamic, 0, 0);
121 return NT_STATUS_OK;
124 static NTSTATUS smb2srv_reply(struct smb2srv_request *req);
126 static void smb2srv_chain_reply(struct smb2srv_request *p_req)
128 NTSTATUS status;
129 struct smb2srv_request *req;
130 uint32_t chain_offset;
131 uint32_t protocol_version;
132 uint16_t buffer_code;
133 uint32_t dynamic_size;
135 chain_offset = p_req->chain_offset;
136 p_req->chain_offset = 0;
138 if (p_req->in.size < (NBT_HDR_SIZE + chain_offset + SMB2_MIN_SIZE)) {
139 DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X\n",
140 chain_offset));
141 smbsrv_terminate_connection(p_req->smb_conn, "Invalid SMB2 chained packet");
142 return;
145 protocol_version = IVAL(p_req->in.buffer, NBT_HDR_SIZE + chain_offset);
146 if (protocol_version != SMB2_MAGIC) {
147 DEBUG(2,("Invalid SMB chained packet: protocol prefix: 0x%08X\n",
148 protocol_version));
149 smbsrv_terminate_connection(p_req->smb_conn, "NON-SMB2 chained packet");
150 return;
153 req = smb2srv_init_request(p_req->smb_conn);
154 if (!req) {
155 smbsrv_terminate_connection(p_req->smb_conn, "SMB2 chained packet - no memory");
156 return;
159 req->in.buffer = talloc_steal(req, p_req->in.buffer);
160 req->in.size = p_req->in.size;
161 req->request_time = p_req->request_time;
162 req->in.allocated = req->in.size;
164 req->in.hdr = req->in.buffer+ NBT_HDR_SIZE + chain_offset;
165 req->in.body = req->in.hdr + SMB2_HDR_BODY;
166 req->in.body_size = req->in.size - (NBT_HDR_SIZE+ chain_offset + SMB2_HDR_BODY);
167 req->in.dynamic = NULL;
169 buffer_code = SVAL(req->in.body, 0);
170 req->in.body_fixed = (buffer_code & ~1);
171 dynamic_size = req->in.body_size - req->in.body_fixed;
173 if (dynamic_size != 0 && (buffer_code & 1)) {
174 req->in.dynamic = req->in.body + req->in.body_fixed;
175 if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
176 DEBUG(1,("SMB2 chained request invalid dynamic size 0x%x\n",
177 dynamic_size));
178 smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
179 return;
183 if (p_req->chained_file_handle) {
184 memcpy(req->_chained_file_handle,
185 p_req->_chained_file_handle,
186 sizeof(req->_chained_file_handle));
187 req->chained_file_handle = req->_chained_file_handle;
191 * TODO: - make sure the length field is 64
192 * - make sure it's a request
195 status = smb2srv_reply(req);
196 if (!NT_STATUS_IS_OK(status)) {
197 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
198 talloc_free(req);
199 return;
203 void smb2srv_send_reply(struct smb2srv_request *req)
205 DATA_BLOB blob;
206 NTSTATUS status;
208 if (req->smb_conn->connection->event.fde == NULL) {
209 /* the socket has been destroyed - no point trying to send a reply! */
210 talloc_free(req);
211 return;
214 if (req->out.size > NBT_HDR_SIZE) {
215 _smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
218 blob = data_blob_const(req->out.buffer, req->out.size);
219 status = packet_send(req->smb_conn->packet, blob);
220 if (!NT_STATUS_IS_OK(status)) {
221 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
223 if (req->chain_offset) {
224 smb2srv_chain_reply(req);
225 return;
227 talloc_free(req);
230 void smb2srv_send_error(struct smb2srv_request *req, NTSTATUS error)
232 NTSTATUS status;
234 if (req->smb_conn->connection->event.fde == NULL) {
235 /* the socket has been destroyed - no point trying to send an error! */
236 talloc_free(req);
237 return;
240 status = smb2srv_setup_reply(req, 8, true, 0);
241 if (!NT_STATUS_IS_OK(status)) {
242 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
243 talloc_free(req);
244 return;
247 SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(error));
249 SSVAL(req->out.body, 0x02, 0);
250 SIVAL(req->out.body, 0x04, 0);
252 smb2srv_send_reply(req);
255 static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
257 uint16_t opcode;
258 uint32_t tid;
259 uint64_t uid;
261 opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
262 req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET);
263 req->seqnum = BVAL(req->in.hdr, SMB2_HDR_SEQNUM);
264 tid = IVAL(req->in.hdr, SMB2_HDR_TID);
265 uid = BVAL(req->in.hdr, SMB2_HDR_UID);
267 req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
268 req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
270 errno = 0;
272 /* TODO: check the seqnum */
274 switch (opcode) {
275 case SMB2_OP_NEGPROT:
276 smb2srv_negprot_recv(req);
277 return NT_STATUS_OK;
278 case SMB2_OP_SESSSETUP:
279 smb2srv_sesssetup_recv(req);
280 return NT_STATUS_OK;
281 case SMB2_OP_LOGOFF:
282 if (!req->session) goto nosession;
283 smb2srv_logoff_recv(req);
284 return NT_STATUS_OK;
285 case SMB2_OP_TCON:
286 if (!req->session) goto nosession;
287 smb2srv_tcon_recv(req);
288 return NT_STATUS_OK;
289 case SMB2_OP_TDIS:
290 if (!req->session) goto nosession;
291 if (!req->tcon) goto notcon;
292 smb2srv_tdis_recv(req);
293 return NT_STATUS_OK;
294 case SMB2_OP_CREATE:
295 if (!req->session) goto nosession;
296 if (!req->tcon) goto notcon;
297 smb2srv_create_recv(req);
298 return NT_STATUS_OK;
299 case SMB2_OP_CLOSE:
300 if (!req->session) goto nosession;
301 if (!req->tcon) goto notcon;
302 smb2srv_close_recv(req);
303 return NT_STATUS_OK;
304 case SMB2_OP_FLUSH:
305 if (!req->session) goto nosession;
306 if (!req->tcon) goto notcon;
307 smb2srv_flush_recv(req);
308 return NT_STATUS_OK;
309 case SMB2_OP_READ:
310 if (!req->session) goto nosession;
311 if (!req->tcon) goto notcon;
312 smb2srv_read_recv(req);
313 return NT_STATUS_OK;
314 case SMB2_OP_WRITE:
315 if (!req->session) goto nosession;
316 if (!req->tcon) goto notcon;
317 smb2srv_write_recv(req);
318 return NT_STATUS_OK;
319 case SMB2_OP_LOCK:
320 if (!req->session) goto nosession;
321 if (!req->tcon) goto notcon;
322 smb2srv_lock_recv(req);
323 return NT_STATUS_OK;
324 case SMB2_OP_IOCTL:
325 if (!req->session) goto nosession;
326 if (!req->tcon) goto notcon;
327 smb2srv_ioctl_recv(req);
328 return NT_STATUS_OK;
329 case SMB2_OP_CANCEL:
330 smb2srv_cancel_recv(req);
331 return NT_STATUS_OK;
332 case SMB2_OP_KEEPALIVE:
333 smb2srv_keepalive_recv(req);
334 return NT_STATUS_OK;
335 case SMB2_OP_FIND:
336 if (!req->session) goto nosession;
337 if (!req->tcon) goto notcon;
338 smb2srv_find_recv(req);
339 return NT_STATUS_OK;
340 case SMB2_OP_NOTIFY:
341 if (!req->session) goto nosession;
342 if (!req->tcon) goto notcon;
343 smb2srv_notify_recv(req);
344 return NT_STATUS_OK;
345 case SMB2_OP_GETINFO:
346 if (!req->session) goto nosession;
347 if (!req->tcon) goto notcon;
348 smb2srv_getinfo_recv(req);
349 return NT_STATUS_OK;
350 case SMB2_OP_SETINFO:
351 if (!req->session) goto nosession;
352 if (!req->tcon) goto notcon;
353 smb2srv_setinfo_recv(req);
354 return NT_STATUS_OK;
355 case SMB2_OP_BREAK:
356 if (!req->session) goto nosession;
357 if (!req->tcon) goto notcon;
358 smb2srv_break_recv(req);
359 return NT_STATUS_OK;
362 DEBUG(1,("Invalid SMB2 opcode: 0x%04X\n", opcode));
363 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 opcode");
364 return NT_STATUS_OK;
366 nosession:
367 smb2srv_send_error(req, NT_STATUS_USER_SESSION_DELETED);
368 return NT_STATUS_OK;
369 notcon:
370 smb2srv_send_error(req, NT_STATUS_NETWORK_NAME_DELETED);
371 return NT_STATUS_OK;
374 NTSTATUS smbsrv_recv_smb2_request(void *private, DATA_BLOB blob)
376 struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
377 struct smb2srv_request *req;
378 struct timeval cur_time = timeval_current();
379 uint32_t protocol_version;
380 uint16_t buffer_code;
381 uint32_t dynamic_size;
383 smb_conn->statistics.last_request_time = cur_time;
385 /* see if its a special NBT packet */
386 if (CVAL(blob.data,0) != 0) {
387 DEBUG(2,("Special NBT packet on SMB2 connection"));
388 smbsrv_terminate_connection(smb_conn, "Special NBT packet on SMB2 connection");
389 return NT_STATUS_OK;
392 if (blob.length < (NBT_HDR_SIZE + SMB2_MIN_SIZE)) {
393 DEBUG(2,("Invalid SMB2 packet length count %ld\n", (long)blob.length));
394 smbsrv_terminate_connection(smb_conn, "Invalid SMB2 packet");
395 return NT_STATUS_OK;
398 protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
399 if (protocol_version != SMB2_MAGIC) {
400 DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n",
401 protocol_version));
402 smbsrv_terminate_connection(smb_conn, "NON-SMB2 packet");
403 return NT_STATUS_OK;
406 req = smb2srv_init_request(smb_conn);
407 NT_STATUS_HAVE_NO_MEMORY(req);
409 req->in.buffer = talloc_steal(req, blob.data);
410 req->in.size = blob.length;
411 req->request_time = cur_time;
412 req->in.allocated = req->in.size;
414 req->in.hdr = req->in.buffer+ NBT_HDR_SIZE;
415 req->in.body = req->in.hdr + SMB2_HDR_BODY;
416 req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE);
417 req->in.dynamic = NULL;
419 buffer_code = SVAL(req->in.body, 0);
420 req->in.body_fixed = (buffer_code & ~1);
421 dynamic_size = req->in.body_size - req->in.body_fixed;
423 if (dynamic_size != 0 && (buffer_code & 1)) {
424 req->in.dynamic = req->in.body + req->in.body_fixed;
425 if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
426 DEBUG(1,("SMB2 request invalid dynamic size 0x%x\n",
427 dynamic_size));
428 smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
429 return NT_STATUS_OK;
434 * TODO: - make sure the length field is 64
435 * - make sure it's a request
438 return smb2srv_reply(req);
441 static NTSTATUS smb2srv_init_pending(struct smbsrv_connection *smb_conn)
443 smb_conn->requests2.idtree_req = idr_init(smb_conn);
444 NT_STATUS_HAVE_NO_MEMORY(smb_conn->requests2.idtree_req);
445 smb_conn->requests2.idtree_limit = 0x00FFFFFF & (UINT32_MAX - 1);
446 smb_conn->requests2.list = NULL;
448 return NT_STATUS_OK;
451 NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req)
453 int id;
455 if (req->pending_id) {
456 return NT_STATUS_INTERNAL_ERROR;
459 id = idr_get_new_above(req->smb_conn->requests2.idtree_req, req,
460 1, req->smb_conn->requests2.idtree_limit);
461 if (id == -1) {
462 return NT_STATUS_INSUFFICIENT_RESOURCES;
465 DLIST_ADD_END(req->smb_conn->requests2.list, req, struct smb2srv_request *);
466 req->pending_id = id;
468 talloc_set_destructor(req, smb2srv_request_deny_destructor);
469 smb2srv_send_error(req, STATUS_PENDING);
470 talloc_set_destructor(req, smb2srv_request_destructor);
472 return NT_STATUS_OK;
475 void smb2srv_cancel_recv(struct smb2srv_request *req)
477 uint32_t pending_id;
478 uint32_t flags;
479 void *p;
480 struct smb2srv_request *r;
482 if (!req->session) goto done;
484 flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
485 pending_id = IVAL(req->in.hdr, SMB2_HDR_PID);
487 if (!(flags & 0x00000002)) {
488 /* TODO: what to do here? */
489 goto done;
492 p = idr_find(req->smb_conn->requests2.idtree_req, pending_id);
493 if (!p) goto done;
495 r = talloc_get_type(p, struct smb2srv_request);
496 if (!r) goto done;
498 if (!r->ntvfs) goto done;
500 ntvfs_cancel(r->ntvfs);
502 done:
503 /* we never generate a reply for a SMB2 Cancel */
504 talloc_free(req);
508 * init the SMB2 protocol related stuff
510 NTSTATUS smbsrv_init_smb2_connection(struct smbsrv_connection *smb_conn)
512 NTSTATUS status;
514 /* now initialise a few default values associated with this smb socket */
515 smb_conn->negotiate.max_send = 0xFFFF;
517 /* this is the size that w2k uses, and it appears to be important for
518 good performance */
519 smb_conn->negotiate.max_recv = lp_max_xmit(global_loadparm);
521 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
523 smb_conn->config.security = SEC_USER;
524 smb_conn->config.nt_status_support = true;
526 status = smbsrv_init_sessions(smb_conn, UINT64_MAX);
527 NT_STATUS_NOT_OK_RETURN(status);
529 status = smb2srv_init_pending(smb_conn);
530 NT_STATUS_NOT_OK_RETURN(status);
532 return NT_STATUS_OK;