e27e622a4a9b1c2e43db5d5b80cba79c463b719e
[kai/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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "system/time.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "smb_server/smb_server.h"
27 #include "smb_server/service_smb_proto.h"
28 #include "smb_server/smb2/smb2_server.h"
29 #include "lib/stream/packet.h"
30
31
32 static struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
33 {
34         struct smb2srv_request *req;
35
36         req = talloc_zero(smb_conn, struct smb2srv_request);
37         if (!req) return NULL;
38
39         req->smb_conn = smb_conn;
40
41         return req;
42 }
43
44 NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint_t body_fixed_size, size_t body_dynamic_size)
45 {
46         req->out.size           = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
47
48         req->out.allocated      = req->out.size + body_dynamic_size;
49         req->out.buffer         = talloc_size(req, req->out.allocated);
50         NT_STATUS_HAVE_NO_MEMORY(req->out.buffer);
51
52         req->out.hdr            = req->out.buffer       + NBT_HDR_SIZE;
53         req->out.body           = req->out.hdr          + SMB2_HDR_BODY;
54         req->out.body_size      = body_fixed_size;
55         req->out.dynamic        = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
56
57         SIVAL(req->out.hdr, 0,                SMB2_MAGIC);
58         SSVAL(req->out.hdr, SMB2_HDR_LENGTH,  SMB2_HDR_BODY);
59         SSVAL(req->out.hdr, SMB2_HDR_PAD1,    0);
60         SIVAL(req->out.hdr, SMB2_HDR_STATUS,  NT_STATUS_V(req->status));
61         SSVAL(req->out.hdr, SMB2_HDR_OPCODE,  SVAL(req->in.hdr, SMB2_HDR_OPCODE));
62         SSVAL(req->out.hdr, SMB2_HDR_PAD2,    0);
63         SIVAL(req->out.hdr, SMB2_HDR_FLAGS,   0x00000001);
64         SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN, 0);
65         SBVAL(req->out.hdr, SMB2_HDR_SEQNUM,  req->seqnum);
66         SIVAL(req->out.hdr, SMB2_HDR_PID,     IVAL(req->in.hdr, SMB2_HDR_PID));
67         SIVAL(req->out.hdr, SMB2_HDR_TID,     IVAL(req->in.hdr, SMB2_HDR_TID));
68         SBVAL(req->out.hdr, SMB2_HDR_UID,     BVAL(req->in.hdr, SMB2_HDR_UID));
69         memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
70
71         /* set the length of the fixed body part and +1 if there's a dynamic part also */
72         SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
73
74         /* 
75          * if we have a dynamic part, make sure the first byte
76          * which is always be part of the packet is initialized
77          */
78         if (body_dynamic_size) {
79                 SCVAL(req->out.dynamic, 0, 0);
80         }
81
82         return NT_STATUS_OK;
83 }
84
85 void smb2srv_send_reply(struct smb2srv_request *req)
86 {
87         DATA_BLOB blob;
88         NTSTATUS status;
89
90         if (req->out.size > NBT_HDR_SIZE) {
91                 _smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
92         }
93
94         blob = data_blob_const(req->out.buffer, req->out.size);
95         status = packet_send(req->smb_conn->packet, blob);
96         if (!NT_STATUS_IS_OK(status)) {
97                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
98         }
99         talloc_free(req);
100 }
101
102 void smb2srv_send_error(struct smb2srv_request *req, NTSTATUS error)
103 {
104         NTSTATUS status;
105
106         status = smb2srv_setup_reply(req, 8, 1);
107         if (!NT_STATUS_IS_OK(status)) {
108                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
109                 talloc_free(req);
110                 return;
111         }
112
113         SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(error));
114
115         SSVAL(req->out.body, 0x02, 0);
116         SIVAL(req->out.body, 0x04, 0);
117
118         smb2srv_send_reply(req);
119 }
120
121 static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
122 {
123         uint16_t opcode;
124         uint32_t tid;
125         uint64_t uid;
126
127         opcode          = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
128         req->seqnum     = BVAL(req->in.hdr, SMB2_HDR_SEQNUM);
129         tid             = IVAL(req->in.hdr, SMB2_HDR_TID);
130         uid             = BVAL(req->in.hdr, SMB2_HDR_UID);
131
132         req->session    = smbsrv_session_find(req->smb_conn, uid, req->request_time);
133         req->tcon       = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
134
135         errno = 0;
136
137         /* TODO: check the seqnum */
138
139         switch (opcode) {
140         case SMB2_OP_NEGPROT:
141                 smb2srv_negprot_recv(req);
142                 return NT_STATUS_OK;
143         case SMB2_OP_SESSSETUP:
144                 smb2srv_sesssetup_recv(req);
145                 return NT_STATUS_OK;
146         case SMB2_OP_LOGOFF:
147                 if (!req->session) goto nosession;
148                 smb2srv_logoff_recv(req);
149                 return NT_STATUS_OK;
150         case SMB2_OP_TCON:
151                 if (!req->session) goto nosession;
152                 smb2srv_tcon_recv(req);
153                 return NT_STATUS_OK;
154         case SMB2_OP_TDIS:
155                 if (!req->session) goto nosession;
156                 if (!req->tcon) goto notcon;
157                 smb2srv_tdis_recv(req);
158                 return NT_STATUS_OK;
159         case SMB2_OP_CREATE:
160                 if (!req->session) goto nosession;
161                 if (!req->tcon) goto notcon;
162                 smb2srv_create_recv(req);
163                 return NT_STATUS_OK;
164         case SMB2_OP_CLOSE:
165                 if (!req->session) goto nosession;
166                 if (!req->tcon) goto notcon;
167                 smb2srv_close_recv(req);
168                 return NT_STATUS_OK;
169         case SMB2_OP_FLUSH:
170                 if (!req->session) goto nosession;
171                 if (!req->tcon) goto notcon;
172                 smb2srv_flush_recv(req);
173                 return NT_STATUS_OK;
174         case SMB2_OP_READ:
175                 if (!req->session) goto nosession;
176                 if (!req->tcon) goto notcon;
177                 smb2srv_read_recv(req);
178                 return NT_STATUS_OK;
179         case SMB2_OP_WRITE:
180                 if (!req->session) goto nosession;
181                 if (!req->tcon) goto notcon;
182                 smb2srv_write_recv(req);
183                 return NT_STATUS_OK;
184         case SMB2_OP_LOCK:
185                 if (!req->session) goto nosession;
186                 if (!req->tcon) goto notcon;
187                 smb2srv_lock_recv(req);
188                 return NT_STATUS_OK;
189         case SMB2_OP_IOCTL:
190                 if (!req->session) goto nosession;
191                 if (!req->tcon) goto notcon;
192                 smb2srv_ioctl_recv(req);
193                 return NT_STATUS_OK;
194         case SMB2_OP_CANCEL:
195                 if (!req->session) goto nosession;
196                 if (!req->tcon) goto notcon;
197                 smb2srv_cancel_recv(req);
198                 return NT_STATUS_OK;
199         case SMB2_OP_KEEPALIVE:
200                 smb2srv_keepalive_recv(req);
201                 return NT_STATUS_OK;
202         case SMB2_OP_FIND:
203                 if (!req->session) goto nosession;
204                 if (!req->tcon) goto notcon;
205                 smb2srv_find_recv(req);
206                 return NT_STATUS_OK;
207         case SMB2_OP_NOTIFY:
208                 if (!req->session) goto nosession;
209                 if (!req->tcon) goto notcon;
210                 smb2srv_notify_recv(req);
211                 return NT_STATUS_OK;
212         case SMB2_OP_GETINFO:
213                 if (!req->session) goto nosession;
214                 if (!req->tcon) goto notcon;
215                 smb2srv_getinfo_recv(req);
216                 return NT_STATUS_OK;
217         case SMB2_OP_SETINFO:
218                 if (!req->session) goto nosession;
219                 if (!req->tcon) goto notcon;
220                 smb2srv_setinfo_recv(req);
221                 return NT_STATUS_OK;
222         case SMB2_OP_BREAK:
223                 if (!req->session) goto nosession;
224                 if (!req->tcon) goto notcon;
225                 smb2srv_break_recv(req);
226                 return NT_STATUS_OK;
227         }
228
229         DEBUG(1,("Invalid SMB2 opcode: 0x%04X\n", opcode));
230         smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 opcode");
231         return NT_STATUS_OK;
232
233 nosession:
234         smb2srv_send_error(req, NT_STATUS_USER_SESSION_DELETED);
235         return NT_STATUS_OK;
236 notcon:
237         smb2srv_send_error(req, NT_STATUS_NETWORK_NAME_DELETED);
238         return NT_STATUS_OK;
239 }
240
241 NTSTATUS smbsrv_recv_smb2_request(void *private, DATA_BLOB blob)
242 {
243         struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
244         struct smb2srv_request *req;
245         struct timeval cur_time = timeval_current();
246         uint32_t protocol_version;
247         uint16_t buffer_code;
248         uint32_t dynamic_size;
249
250         smb_conn->statistics.last_request_time = cur_time;
251
252         /* see if its a special NBT packet */
253         if (CVAL(blob.data,0) != 0) {
254                 DEBUG(2,("Special NBT packet on SMB2 connection"));
255                 smbsrv_terminate_connection(smb_conn, "Special NBT packet on SMB2 connection");
256                 return NT_STATUS_OK;
257         }
258
259         if (blob.length < (NBT_HDR_SIZE + SMB2_MIN_SIZE)) {
260                 DEBUG(2,("Invalid SMB2 packet length count %ld\n", (long)blob.length));
261                 smbsrv_terminate_connection(smb_conn, "Invalid SMB2 packet");
262                 return NT_STATUS_OK;
263         }
264
265         protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
266
267         if (protocol_version != SMB2_MAGIC) {
268                 DEBUG(2,("Invalid SMB packet: protocl prefix: 0x%08X\n", protocol_version));
269                 smbsrv_terminate_connection(smb_conn, "NON-SMB2 packet");
270                 return NT_STATUS_OK;
271         }
272
273         req = smb2srv_init_request(smb_conn);
274         NT_STATUS_HAVE_NO_MEMORY(req);
275
276         req->in.buffer          = talloc_steal(req, blob.data);
277         req->in.size            = blob.length;
278         req->request_time       = cur_time;
279         req->in.allocated       = req->in.size;
280
281         req->in.hdr             = req->in.buffer+ NBT_HDR_SIZE;
282         req->in.body            = req->in.hdr   + SMB2_HDR_BODY;
283         req->in.body_size       = req->in.size  - (SMB2_HDR_BODY+NBT_HDR_SIZE);
284         req->in.dynamic         = NULL;
285
286         buffer_code             = SVAL(req->in.body, 0);
287         dynamic_size            = req->in.body_size - (buffer_code & ~1);
288
289         if (dynamic_size != 0 && (buffer_code & 1)) {
290                 req->in.dynamic = req->in.body + (buffer_code & ~1);
291                 if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
292                         DEBUG(1,("SMB2 request invalid dynamic size 0x%x\n", 
293                                  dynamic_size));
294                         smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
295                         return NT_STATUS_OK;
296                 }
297         }
298
299         /* 
300          * TODO: - make sure the length field is 64
301          *       - make sure it's a request
302          */
303
304         return smb2srv_reply(req);
305 }
306
307 /*
308  * init the SMB2 protocol related stuff
309  */
310 NTSTATUS smbsrv_init_smb2_connection(struct smbsrv_connection *smb_conn)
311 {
312         NTSTATUS status;
313
314         /* now initialise a few default values associated with this smb socket */
315         smb_conn->negotiate.max_send = 0xFFFF;
316
317         /* this is the size that w2k uses, and it appears to be important for
318            good performance */
319         smb_conn->negotiate.max_recv = lp_max_xmit();
320
321         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
322
323         smb_conn->config.security = SEC_USER;
324         smb_conn->config.nt_status_support = True;
325
326         status = smbsrv_init_sessions(smb_conn, UINT64_MAX);
327         NT_STATUS_NOT_OK_RETURN(status);
328
329         return NT_STATUS_OK;
330         
331 }