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