a8c0e6f7862bc5061406d3a3b0bb8739b13d0178
[gd/samba-autobuild/.git] / source4 / smb_server / smb2 / receive.c
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/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
32 static int smb2srv_request_destructor(struct smb2srv_request *req)
33 {
34         DLIST_REMOVE(req->smb_conn->requests2.list, req);
35         if (req->pending_id) {
36                 idr_remove(req->smb_conn->requests2.idtree_req, req->pending_id);
37         }
38         return 0;
39 }
40
41 static int smb2srv_request_deny_destructor(struct smb2srv_request *req)
42 {
43         return -1;
44 }
45
46 struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
47 {
48         struct smb2srv_request *req;
49
50         req = talloc_zero(smb_conn, struct smb2srv_request);
51         if (!req) return NULL;
52
53         req->smb_conn = smb_conn;
54
55         talloc_set_destructor(req, smb2srv_request_destructor);
56
57         return req;
58 }
59
60 NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_size,
61                              BOOL body_dynamic_present, uint32_t body_dynamic_size)
62 {
63         uint32_t flags = 0x00000001;
64         uint32_t pid = IVAL(req->in.hdr, SMB2_HDR_PID);
65         uint32_t tid = IVAL(req->in.hdr, SMB2_HDR_TID);
66
67         if (req->pending_id) {
68                 flags |= 0x00000002;
69                 pid = req->pending_id;
70                 tid = 0;
71         }
72
73         if (body_dynamic_present) {
74                 if (body_dynamic_size == 0) {
75                         body_dynamic_size = 1;
76                 }
77         } else {
78                 body_dynamic_size = 0;
79         }
80
81         req->out.size           = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
82
83         req->out.allocated      = req->out.size + body_dynamic_size;
84         req->out.buffer         = talloc_size(req, req->out.allocated);
85         NT_STATUS_HAVE_NO_MEMORY(req->out.buffer);
86
87         req->out.hdr            = req->out.buffer       + NBT_HDR_SIZE;
88         req->out.body           = req->out.hdr          + SMB2_HDR_BODY;
89         req->out.body_fixed     = body_fixed_size;
90         req->out.body_size      = body_fixed_size;
91         req->out.dynamic        = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
92
93         SIVAL(req->out.hdr, 0,                          SMB2_MAGIC);
94         SSVAL(req->out.hdr, SMB2_HDR_LENGTH,            SMB2_HDR_BODY);
95         SSVAL(req->out.hdr, SMB2_HDR_PAD1,              0);
96         SIVAL(req->out.hdr, SMB2_HDR_STATUS,            NT_STATUS_V(req->status));
97         SSVAL(req->out.hdr, SMB2_HDR_OPCODE,            SVAL(req->in.hdr, SMB2_HDR_OPCODE));
98         SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,          0x0001);
99         SIVAL(req->out.hdr, SMB2_HDR_FLAGS,             flags);
100         SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET,      0);
101         SBVAL(req->out.hdr, SMB2_HDR_SEQNUM,            req->seqnum);
102         SIVAL(req->out.hdr, SMB2_HDR_PID,               pid);
103         SIVAL(req->out.hdr, SMB2_HDR_TID,               tid);
104         SBVAL(req->out.hdr, SMB2_HDR_UID,               BVAL(req->in.hdr, SMB2_HDR_UID));
105         memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
106
107         /* set the length of the fixed body part and +1 if there's a dynamic part also */
108         SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
109
110         /* 
111          * if we have a dynamic part, make sure the first byte
112          * which is always be part of the packet is initialized
113          */
114         if (body_dynamic_size) {
115                 req->out.size += 1;
116                 SCVAL(req->out.dynamic, 0, 0);
117         }
118
119         return NT_STATUS_OK;
120 }
121
122 static NTSTATUS smb2srv_reply(struct smb2srv_request *req);
123
124 static void smb2srv_chain_reply(struct smb2srv_request *p_req)
125 {
126         NTSTATUS status;
127         struct smb2srv_request *req;
128         uint32_t chain_offset;
129         uint32_t protocol_version;
130         uint16_t buffer_code;
131         uint32_t dynamic_size;
132
133         chain_offset = p_req->chain_offset;
134         p_req->chain_offset = 0;
135
136         if (p_req->in.size < (NBT_HDR_SIZE + chain_offset + SMB2_MIN_SIZE)) {
137                 DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X\n",
138                         chain_offset));
139                 smbsrv_terminate_connection(p_req->smb_conn, "Invalid SMB2 chained packet");
140                 return;
141         }
142
143         protocol_version = IVAL(p_req->in.buffer, NBT_HDR_SIZE + chain_offset);
144         if (protocol_version != SMB2_MAGIC) {
145                 DEBUG(2,("Invalid SMB chained packet: protocol prefix: 0x%08X\n",
146                          protocol_version));
147                 smbsrv_terminate_connection(p_req->smb_conn, "NON-SMB2 chained packet");
148                 return;
149         }
150
151         req = smb2srv_init_request(p_req->smb_conn);
152         if (!req) {
153                 smbsrv_terminate_connection(p_req->smb_conn, "SMB2 chained packet - no memory");
154                 return;
155         }
156
157         req->in.buffer          = talloc_steal(req, p_req->in.buffer);
158         req->in.size            = p_req->in.size;
159         req->request_time       = p_req->request_time;
160         req->in.allocated       = req->in.size;
161
162         req->in.hdr             = req->in.buffer+ NBT_HDR_SIZE + chain_offset;
163         req->in.body            = req->in.hdr   + SMB2_HDR_BODY;
164         req->in.body_size       = req->in.size  - (NBT_HDR_SIZE+ chain_offset + SMB2_HDR_BODY);
165         req->in.dynamic         = NULL;
166
167         buffer_code             = SVAL(req->in.body, 0);
168         req->in.body_fixed      = (buffer_code & ~1);
169         dynamic_size            = req->in.body_size - req->in.body_fixed;
170
171         if (dynamic_size != 0 && (buffer_code & 1)) {
172                 req->in.dynamic = req->in.body + req->in.body_fixed;
173                 if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
174                         DEBUG(1,("SMB2 chained request invalid dynamic size 0x%x\n", 
175                                  dynamic_size));
176                         smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
177                         return;
178                 }
179         }
180
181         if (p_req->chained_file_handle) {
182                 memcpy(req->_chained_file_handle,
183                        p_req->_chained_file_handle,
184                        sizeof(req->_chained_file_handle));
185                 req->chained_file_handle = req->_chained_file_handle;
186         }
187
188         /* 
189          * TODO: - make sure the length field is 64
190          *       - make sure it's a request
191          */
192
193         status = smb2srv_reply(req);
194         if (!NT_STATUS_IS_OK(status)) {
195                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
196                 talloc_free(req);
197                 return;
198         }
199 }
200
201 void smb2srv_send_reply(struct smb2srv_request *req)
202 {
203         DATA_BLOB blob;
204         NTSTATUS status;
205
206         if (req->smb_conn->connection->event.fde == NULL) {
207                 /* the socket has been destroyed - no point trying to send a reply! */
208                 talloc_free(req);
209                 return;
210         }
211
212         if (req->out.size > NBT_HDR_SIZE) {
213                 _smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
214         }
215
216         blob = data_blob_const(req->out.buffer, req->out.size);
217         status = packet_send(req->smb_conn->packet, blob);
218         if (!NT_STATUS_IS_OK(status)) {
219                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
220         }
221         if (req->chain_offset) {
222                 smb2srv_chain_reply(req);
223                 return;
224         }
225         talloc_free(req);
226 }
227
228 void smb2srv_send_error(struct smb2srv_request *req, NTSTATUS error)
229 {
230         NTSTATUS status;
231
232         if (req->smb_conn->connection->event.fde == NULL) {
233                 /* the socket has been destroyed - no point trying to send an error! */
234                 talloc_free(req);
235                 return;
236         }
237
238         status = smb2srv_setup_reply(req, 8, True, 0);
239         if (!NT_STATUS_IS_OK(status)) {
240                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
241                 talloc_free(req);
242                 return;
243         }
244
245         SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(error));
246
247         SSVAL(req->out.body, 0x02, 0);
248         SIVAL(req->out.body, 0x04, 0);
249
250         smb2srv_send_reply(req);
251 }
252
253 static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
254 {
255         uint16_t opcode;
256         uint32_t tid;
257         uint64_t uid;
258
259         opcode                  = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
260         req->chain_offset       = IVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET);
261         req->seqnum             = BVAL(req->in.hdr, SMB2_HDR_SEQNUM);
262         tid                     = IVAL(req->in.hdr, SMB2_HDR_TID);
263         uid                     = BVAL(req->in.hdr, SMB2_HDR_UID);
264
265         req->session    = smbsrv_session_find(req->smb_conn, uid, req->request_time);
266         req->tcon       = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
267
268         errno = 0;
269
270         /* TODO: check the seqnum */
271
272         switch (opcode) {
273         case SMB2_OP_NEGPROT:
274                 smb2srv_negprot_recv(req);
275                 return NT_STATUS_OK;
276         case SMB2_OP_SESSSETUP:
277                 smb2srv_sesssetup_recv(req);
278                 return NT_STATUS_OK;
279         case SMB2_OP_LOGOFF:
280                 if (!req->session) goto nosession;
281                 smb2srv_logoff_recv(req);
282                 return NT_STATUS_OK;
283         case SMB2_OP_TCON:
284                 if (!req->session) goto nosession;
285                 smb2srv_tcon_recv(req);
286                 return NT_STATUS_OK;
287         case SMB2_OP_TDIS:
288                 if (!req->session) goto nosession;
289                 if (!req->tcon) goto notcon;
290                 smb2srv_tdis_recv(req);
291                 return NT_STATUS_OK;
292         case SMB2_OP_CREATE:
293                 if (!req->session) goto nosession;
294                 if (!req->tcon) goto notcon;
295                 smb2srv_create_recv(req);
296                 return NT_STATUS_OK;
297         case SMB2_OP_CLOSE:
298                 if (!req->session) goto nosession;
299                 if (!req->tcon) goto notcon;
300                 smb2srv_close_recv(req);
301                 return NT_STATUS_OK;
302         case SMB2_OP_FLUSH:
303                 if (!req->session) goto nosession;
304                 if (!req->tcon) goto notcon;
305                 smb2srv_flush_recv(req);
306                 return NT_STATUS_OK;
307         case SMB2_OP_READ:
308                 if (!req->session) goto nosession;
309                 if (!req->tcon) goto notcon;
310                 smb2srv_read_recv(req);
311                 return NT_STATUS_OK;
312         case SMB2_OP_WRITE:
313                 if (!req->session) goto nosession;
314                 if (!req->tcon) goto notcon;
315                 smb2srv_write_recv(req);
316                 return NT_STATUS_OK;
317         case SMB2_OP_LOCK:
318                 if (!req->session) goto nosession;
319                 if (!req->tcon) goto notcon;
320                 smb2srv_lock_recv(req);
321                 return NT_STATUS_OK;
322         case SMB2_OP_IOCTL:
323                 if (!req->session) goto nosession;
324                 if (!req->tcon) goto notcon;
325                 smb2srv_ioctl_recv(req);
326                 return NT_STATUS_OK;
327         case SMB2_OP_CANCEL:
328                 smb2srv_cancel_recv(req);
329                 return NT_STATUS_OK;
330         case SMB2_OP_KEEPALIVE:
331                 smb2srv_keepalive_recv(req);
332                 return NT_STATUS_OK;
333         case SMB2_OP_FIND:
334                 if (!req->session) goto nosession;
335                 if (!req->tcon) goto notcon;
336                 smb2srv_find_recv(req);
337                 return NT_STATUS_OK;
338         case SMB2_OP_NOTIFY:
339                 if (!req->session) goto nosession;
340                 if (!req->tcon) goto notcon;
341                 smb2srv_notify_recv(req);
342                 return NT_STATUS_OK;
343         case SMB2_OP_GETINFO:
344                 if (!req->session) goto nosession;
345                 if (!req->tcon) goto notcon;
346                 smb2srv_getinfo_recv(req);
347                 return NT_STATUS_OK;
348         case SMB2_OP_SETINFO:
349                 if (!req->session) goto nosession;
350                 if (!req->tcon) goto notcon;
351                 smb2srv_setinfo_recv(req);
352                 return NT_STATUS_OK;
353         case SMB2_OP_BREAK:
354                 if (!req->session) goto nosession;
355                 if (!req->tcon) goto notcon;
356                 smb2srv_break_recv(req);
357                 return NT_STATUS_OK;
358         }
359
360         DEBUG(1,("Invalid SMB2 opcode: 0x%04X\n", opcode));
361         smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 opcode");
362         return NT_STATUS_OK;
363
364 nosession:
365         smb2srv_send_error(req, NT_STATUS_USER_SESSION_DELETED);
366         return NT_STATUS_OK;
367 notcon:
368         smb2srv_send_error(req, NT_STATUS_NETWORK_NAME_DELETED);
369         return NT_STATUS_OK;
370 }
371
372 NTSTATUS smbsrv_recv_smb2_request(void *private, DATA_BLOB blob)
373 {
374         struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
375         struct smb2srv_request *req;
376         struct timeval cur_time = timeval_current();
377         uint32_t protocol_version;
378         uint16_t buffer_code;
379         uint32_t dynamic_size;
380
381         smb_conn->statistics.last_request_time = cur_time;
382
383         /* see if its a special NBT packet */
384         if (CVAL(blob.data,0) != 0) {
385                 DEBUG(2,("Special NBT packet on SMB2 connection"));
386                 smbsrv_terminate_connection(smb_conn, "Special NBT packet on SMB2 connection");
387                 return NT_STATUS_OK;
388         }
389
390         if (blob.length < (NBT_HDR_SIZE + SMB2_MIN_SIZE)) {
391                 DEBUG(2,("Invalid SMB2 packet length count %ld\n", (long)blob.length));
392                 smbsrv_terminate_connection(smb_conn, "Invalid SMB2 packet");
393                 return NT_STATUS_OK;
394         }
395
396         protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
397         if (protocol_version != SMB2_MAGIC) {
398                 DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n",
399                          protocol_version));
400                 smbsrv_terminate_connection(smb_conn, "NON-SMB2 packet");
401                 return NT_STATUS_OK;
402         }
403
404         req = smb2srv_init_request(smb_conn);
405         NT_STATUS_HAVE_NO_MEMORY(req);
406
407         req->in.buffer          = talloc_steal(req, blob.data);
408         req->in.size            = blob.length;
409         req->request_time       = cur_time;
410         req->in.allocated       = req->in.size;
411
412         req->in.hdr             = req->in.buffer+ NBT_HDR_SIZE;
413         req->in.body            = req->in.hdr   + SMB2_HDR_BODY;
414         req->in.body_size       = req->in.size  - (SMB2_HDR_BODY+NBT_HDR_SIZE);
415         req->in.dynamic         = NULL;
416
417         buffer_code             = SVAL(req->in.body, 0);
418         req->in.body_fixed      = (buffer_code & ~1);
419         dynamic_size            = req->in.body_size - req->in.body_fixed;
420
421         if (dynamic_size != 0 && (buffer_code & 1)) {
422                 req->in.dynamic = req->in.body + req->in.body_fixed;
423                 if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
424                         DEBUG(1,("SMB2 request invalid dynamic size 0x%x\n", 
425                                  dynamic_size));
426                         smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
427                         return NT_STATUS_OK;
428                 }
429         }
430
431         /* 
432          * TODO: - make sure the length field is 64
433          *       - make sure it's a request
434          */
435
436         return smb2srv_reply(req);
437 }
438
439 static NTSTATUS smb2srv_init_pending(struct smbsrv_connection *smb_conn)
440 {
441         smb_conn->requests2.idtree_req = idr_init(smb_conn);
442         NT_STATUS_HAVE_NO_MEMORY(smb_conn->requests2.idtree_req);
443         smb_conn->requests2.idtree_limit        = 0x00FFFFFF & (UINT32_MAX - 1);
444         smb_conn->requests2.list                = NULL;
445
446         return NT_STATUS_OK;
447 }
448
449 NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req)
450 {
451         int id;
452
453         if (req->pending_id) {
454                 return NT_STATUS_INTERNAL_ERROR;
455         }
456
457         id = idr_get_new_above(req->smb_conn->requests2.idtree_req, req, 
458                                1, req->smb_conn->requests2.idtree_limit);
459         if (id == -1) {
460                 return NT_STATUS_INSUFFICIENT_RESOURCES;
461         }
462
463         DLIST_ADD_END(req->smb_conn->requests2.list, req, struct smb2srv_request *);
464         req->pending_id = id;
465
466         talloc_set_destructor(req, smb2srv_request_deny_destructor);
467         smb2srv_send_error(req, STATUS_PENDING);
468         talloc_set_destructor(req, smb2srv_request_destructor);
469
470         return NT_STATUS_OK;
471 }
472
473 void smb2srv_cancel_recv(struct smb2srv_request *req)
474 {
475         uint32_t pending_id;
476         uint32_t flags;
477         void *p;
478         struct smb2srv_request *r;
479
480         if (!req->session) goto done;
481
482         flags           = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
483         pending_id      = IVAL(req->in.hdr, SMB2_HDR_PID);
484
485         if (!(flags & 0x00000002)) {
486                 /* TODO: what to do here? */
487                 goto done;
488         }
489  
490         p = idr_find(req->smb_conn->requests2.idtree_req, pending_id);
491         if (!p) goto done;
492
493         r = talloc_get_type(p, struct smb2srv_request);
494         if (!r) goto done;
495
496         if (!r->ntvfs) goto done;
497
498         ntvfs_cancel(r->ntvfs);
499
500 done:
501         /* we never generate a reply for a SMB2 Cancel */
502         talloc_free(req);
503 }
504
505 /*
506  * init the SMB2 protocol related stuff
507  */
508 NTSTATUS smbsrv_init_smb2_connection(struct smbsrv_connection *smb_conn)
509 {
510         NTSTATUS status;
511
512         /* now initialise a few default values associated with this smb socket */
513         smb_conn->negotiate.max_send = 0xFFFF;
514
515         /* this is the size that w2k uses, and it appears to be important for
516            good performance */
517         smb_conn->negotiate.max_recv = lp_max_xmit();
518
519         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
520
521         smb_conn->config.security = SEC_USER;
522         smb_conn->config.nt_status_support = True;
523
524         status = smbsrv_init_sessions(smb_conn, UINT64_MAX);
525         NT_STATUS_NOT_OK_RETURN(status);
526
527         status = smb2srv_init_pending(smb_conn);
528         NT_STATUS_NOT_OK_RETURN(status);
529
530         return NT_STATUS_OK;
531         
532 }