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