e853743b2f6612f349ae916b63b6fa90a3092b45
[jelmer/samba4-debian.git] / source / smb_server / smb2 / fileio.c
1 /* 
2    Unix SMB2 implementation.
3    
4    Copyright (C) Stefan Metzmacher      2005
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "libcli/smb2/smb2.h"
22 #include "libcli/smb2/smb2_calls.h"
23 #include "smb_server/smb_server.h"
24 #include "smb_server/service_smb_proto.h"
25 #include "smb_server/smb2/smb2_server.h"
26 #include "ntvfs/ntvfs.h"
27 #include "param/param.h"
28
29 static void smb2srv_create_send(struct ntvfs_request *ntvfs)
30 {
31         struct smb2srv_request *req;
32         union smb_open *io;
33
34         SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_open);
35         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x58, true, io->smb2.out.blob.length));
36
37         SSVAL(req->out.body,    0x02,   io->smb2.out.oplock_flags);
38         SIVAL(req->out.body,    0x04,   io->smb2.out.create_action);
39         SBVAL(req->out.body,    0x08,   io->smb2.out.create_time);
40         SBVAL(req->out.body,    0x10,   io->smb2.out.access_time);
41         SBVAL(req->out.body,    0x18,   io->smb2.out.write_time);
42         SBVAL(req->out.body,    0x20,   io->smb2.out.change_time);
43         SBVAL(req->out.body,    0x28,   io->smb2.out.alloc_size);
44         SBVAL(req->out.body,    0x30,   io->smb2.out.size);
45         SIVAL(req->out.body,    0x38,   io->smb2.out.file_attr);
46         SIVAL(req->out.body,    0x3C,   io->smb2.out._pad);
47         smb2srv_push_handle(req->out.body, 0x40, io->smb2.out.file.ntvfs);
48         SMB2SRV_CHECK(smb2_push_o32s32_blob(&req->out, 0x50, io->smb2.out.blob));
49
50         /* also setup the chained file handle */
51         req->chained_file_handle = req->_chained_file_handle;
52         smb2srv_push_handle(req->chained_file_handle, 0, io->smb2.out.file.ntvfs);
53
54         smb2srv_send_reply(req);
55 }
56
57 void smb2srv_create_recv(struct smb2srv_request *req)
58 {
59         union smb_open *io;
60         DATA_BLOB blob;
61
62         SMB2SRV_CHECK_BODY_SIZE(req, 0x38, true);
63         SMB2SRV_TALLOC_IO_PTR(io, union smb_open);
64         SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_create_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
65
66         io->smb2.level                  = RAW_OPEN_SMB2;
67         io->smb2.in.oplock_flags        = SVAL(req->in.body, 0x02);
68         io->smb2.in.impersonation       = IVAL(req->in.body, 0x04);
69         io->smb2.in.unknown3[0]         = IVAL(req->in.body, 0x08);
70         io->smb2.in.unknown3[1]         = IVAL(req->in.body, 0x0C);
71         io->smb2.in.unknown3[2]         = IVAL(req->in.body, 0x10);
72         io->smb2.in.unknown3[3]         = IVAL(req->in.body, 0x14);
73         io->smb2.in.access_mask         = IVAL(req->in.body, 0x18);
74         io->smb2.in.file_attr           = IVAL(req->in.body, 0x1C);
75         io->smb2.in.share_access        = IVAL(req->in.body, 0x20);
76         io->smb2.in.open_disposition    = IVAL(req->in.body, 0x24);
77         io->smb2.in.create_options      = IVAL(req->in.body, 0x28);
78         SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, io, req->in.body+0x2C, &io->smb2.in.fname));
79         SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req->in, io, req->in.body+0x30, &blob));
80         /* TODO: parse the blob */
81         ZERO_STRUCT(io->smb2.in.eas);
82
83         SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io));
84 }
85
86 static void smb2srv_close_send(struct ntvfs_request *ntvfs)
87 {
88         struct smb2srv_request *req;
89         union smb_close *io;
90
91         SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_close);
92         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x3C, false, 0));
93
94         SSVAL(req->out.body,    0x02,   io->smb2.out.flags);
95         SIVAL(req->out.body,    0x04,   io->smb2.out._pad);
96         SBVAL(req->out.body,    0x08,   io->smb2.out.create_time);
97         SBVAL(req->out.body,    0x10,   io->smb2.out.access_time);
98         SBVAL(req->out.body,    0x18,   io->smb2.out.write_time);
99         SBVAL(req->out.body,    0x20,   io->smb2.out.change_time);
100         SBVAL(req->out.body,    0x28,   io->smb2.out.alloc_size);
101         SBVAL(req->out.body,    0x30,   io->smb2.out.size);
102         SIVAL(req->out.body,    0x38,   io->smb2.out.file_attr);
103
104         smb2srv_send_reply(req);
105 }
106
107 void smb2srv_close_recv(struct smb2srv_request *req)
108 {
109         union smb_close *io;
110
111         SMB2SRV_CHECK_BODY_SIZE(req, 0x18, false);
112         SMB2SRV_TALLOC_IO_PTR(io, union smb_close);
113         SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_close_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
114
115         io->smb2.level                  = RAW_CLOSE_SMB2;
116         io->smb2.in.flags               = SVAL(req->in.body, 0x02);
117         io->smb2.in._pad                = IVAL(req->in.body, 0x04);
118         io->smb2.in.file.ntvfs          = smb2srv_pull_handle(req, req->in.body, 0x08);
119
120         SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs);
121         SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_close(req->ntvfs, io));
122 }
123
124 static void smb2srv_flush_send(struct ntvfs_request *ntvfs)
125 {
126         struct smb2srv_request *req;
127         union smb_flush *io;
128
129         SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_flush);
130         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x04, false, 0));
131
132         SSVAL(req->out.body,    0x02,   0);
133
134         smb2srv_send_reply(req);
135 }
136
137 void smb2srv_flush_recv(struct smb2srv_request *req)
138 {
139         union smb_flush *io;
140         uint16_t _pad;
141
142         SMB2SRV_CHECK_BODY_SIZE(req, 0x18, false);
143         SMB2SRV_TALLOC_IO_PTR(io, union smb_flush);
144         SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_flush_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
145
146         io->smb2.level                  = RAW_FLUSH_SMB2;
147         _pad                            = SVAL(req->in.body, 0x02);
148         io->smb2.in.unknown             = IVAL(req->in.body, 0x04);
149         io->smb2.in.file.ntvfs          = smb2srv_pull_handle(req, req->in.body, 0x08);
150
151         SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs);
152         SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_flush(req->ntvfs, io));
153 }
154
155 static void smb2srv_read_send(struct ntvfs_request *ntvfs)
156 {
157         struct smb2srv_request *req;
158         union smb_read *io;
159
160         SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_read);
161         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x10, true, io->smb2.out.data.length));
162
163         /* TODO: avoid the memcpy */
164         SMB2SRV_CHECK(smb2_push_o16s32_blob(&req->out, 0x02, io->smb2.out.data));
165         SBVAL(req->out.body,    0x08,   io->smb2.out.unknown1);
166
167         smb2srv_send_reply(req);
168 }
169
170 void smb2srv_read_recv(struct smb2srv_request *req)
171 {
172         union smb_read *io;
173
174         SMB2SRV_CHECK_BODY_SIZE(req, 0x30, true);
175         SMB2SRV_TALLOC_IO_PTR(io, union smb_read);
176         SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_read_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
177
178         io->smb2.level                  = RAW_READ_SMB2;
179         io->smb2.in._pad                = SVAL(req->in.body, 0x02);
180         io->smb2.in.length              = IVAL(req->in.body, 0x04);
181         io->smb2.in.offset              = BVAL(req->in.body, 0x08);
182         io->smb2.in.file.ntvfs          = smb2srv_pull_handle(req, req->in.body, 0x10);
183         io->smb2.in.unknown1            = BVAL(req->in.body, 0x20);
184         io->smb2.in.unknown2            = BVAL(req->in.body, 0x28);
185
186         SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs);
187
188         /* preallocate the buffer for the backends */
189         io->smb2.out.data = data_blob_talloc(io, NULL, io->smb2.in.length);
190         if (io->smb2.out.data.length != io->smb2.in.length) {
191                 SMB2SRV_CHECK(NT_STATUS_NO_MEMORY);
192         }
193
194         SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_read(req->ntvfs, io));
195 }
196
197 static void smb2srv_write_send(struct ntvfs_request *ntvfs)
198 {
199         struct smb2srv_request *req;
200         union smb_write *io;
201
202         SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_write);
203         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x10, true, 0));
204
205         SSVAL(req->out.body,    0x02,   io->smb2.out._pad);
206         SIVAL(req->out.body,    0x04,   io->smb2.out.nwritten);
207         SBVAL(req->out.body,    0x08,   io->smb2.out.unknown1);
208
209         smb2srv_send_reply(req);
210 }
211
212 void smb2srv_write_recv(struct smb2srv_request *req)
213 {
214         union smb_write *io;
215
216         SMB2SRV_CHECK_BODY_SIZE(req, 0x30, true);
217         SMB2SRV_TALLOC_IO_PTR(io, union smb_write);
218         SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_write_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
219
220         /* TODO: avoid the memcpy */
221         io->smb2.level                  = RAW_WRITE_SMB2;
222         SMB2SRV_CHECK(smb2_pull_o16s32_blob(&req->in, io, req->in.body+0x02, &io->smb2.in.data));
223         io->smb2.in.offset              = BVAL(req->in.body, 0x08);
224         io->smb2.in.file.ntvfs          = smb2srv_pull_handle(req, req->in.body, 0x10);
225         io->smb2.in.unknown1            = BVAL(req->in.body, 0x20);
226         io->smb2.in.unknown2            = BVAL(req->in.body, 0x28);
227
228         SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs);
229         SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_write(req->ntvfs, io));
230 }
231
232 static void smb2srv_lock_send(struct ntvfs_request *ntvfs)
233 {
234         struct smb2srv_request *req;
235         union smb_lock *io;
236
237         SMB2SRV_CHECK_ASYNC_STATUS_ERR(io, union smb_lock);
238         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x04, false, 0));
239
240         SSVAL(req->out.body,    0x02,   io->smb2.out.unknown1);
241
242         smb2srv_send_reply(req);
243 }
244
245 void smb2srv_lock_recv(struct smb2srv_request *req)
246 {
247         union smb_lock *io;
248
249         SMB2SRV_CHECK_BODY_SIZE(req, 0x30, false);
250         SMB2SRV_TALLOC_IO_PTR(io, union smb_lock);
251         SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_lock_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
252
253         io->smb2.level                  = RAW_LOCK_SMB2;
254
255         io->smb2.in.unknown1            = SVAL(req->in.body, 0x02);
256         io->smb2.in.unknown2            = IVAL(req->in.body, 0x04);
257         io->smb2.in.file.ntvfs          = smb2srv_pull_handle(req, req->in.body, 0x08);
258         io->smb2.in.offset              = BVAL(req->in.body, 0x18);
259         io->smb2.in.count               = BVAL(req->in.body, 0x20);
260         io->smb2.in.unknown5            = IVAL(req->in.body, 0x24);
261         io->smb2.in.flags               = IVAL(req->in.body, 0x28);
262
263         SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs);
264         SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_lock(req->ntvfs, io));
265 }
266
267 static void smb2srv_ioctl_send(struct ntvfs_request *ntvfs)
268 {
269         struct smb2srv_request *req;
270         union smb_ioctl *io;
271
272         SMB2SRV_CHECK_ASYNC_STATUS_ERR(io, union smb_ioctl);
273         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x30, true, 0));
274
275         SSVAL(req->out.body,    0x02,   io->smb2.out._pad);
276         SIVAL(req->out.body,    0x04,   io->smb2.out.function);
277         if (io->smb2.level == RAW_IOCTL_SMB2_NO_HANDLE) {
278                 struct smb2_handle h;
279                 h.data[0] = UINT64_MAX;
280                 h.data[1] = UINT64_MAX;
281                 smb2_push_handle(req->out.body + 0x08, &h);
282         } else {
283                 smb2srv_push_handle(req->out.body, 0x08,io->smb2.in.file.ntvfs);
284         }
285         SMB2SRV_CHECK(smb2_push_o32s32_blob(&req->out, 0x18, io->smb2.out.in));
286         SMB2SRV_CHECK(smb2_push_o32s32_blob(&req->out, 0x20, io->smb2.out.out));
287         SIVAL(req->out.body,    0x28,   io->smb2.out.unknown2);
288         SIVAL(req->out.body,    0x2C,   io->smb2.out.unknown3);
289
290         smb2srv_send_reply(req);
291 }
292
293 void smb2srv_ioctl_recv(struct smb2srv_request *req)
294 {
295         union smb_ioctl *io;
296         struct smb2_handle h;
297
298         SMB2SRV_CHECK_BODY_SIZE(req, 0x38, true);
299         SMB2SRV_TALLOC_IO_PTR(io, union smb_ioctl);
300         SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_ioctl_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
301
302         /* TODO: avoid the memcpy */
303         io->smb2.in._pad                = SVAL(req->in.body, 0x02);
304         io->smb2.in.function            = IVAL(req->in.body, 0x04);
305         /* file handle ... */
306         SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req->in, io, req->in.body+0x18, &io->smb2.in.out));
307         io->smb2.in.unknown2            = IVAL(req->in.body, 0x20);
308         SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req->in, io, req->in.body+0x24, &io->smb2.in.in));
309         io->smb2.in.max_response_size   = IVAL(req->in.body, 0x2C);
310         io->smb2.in.flags               = BVAL(req->in.body, 0x30);
311
312         smb2_pull_handle(req->in.body + 0x08, &h);
313         if (h.data[0] == UINT64_MAX && h.data[1] == UINT64_MAX) {
314                 io->smb2.level          = RAW_IOCTL_SMB2_NO_HANDLE;
315         } else {
316                 io->smb2.level          = RAW_IOCTL_SMB2;
317                 io->smb2.in.file.ntvfs  = smb2srv_pull_handle(req, req->in.body, 0x08);
318                 SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs);
319         }
320
321         SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req->ntvfs, io));
322 }
323
324 static void smb2srv_notify_send(struct ntvfs_request *ntvfs)
325 {
326         struct smb2srv_request *req;
327         union smb_notify *io;
328         size_t size = 0;
329         int i;
330         uint8_t *p;
331         DATA_BLOB blob = data_blob(NULL, 0);
332
333         SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_notify);
334         SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, true, 0));
335
336 #define MAX_BYTES_PER_CHAR 3
337         
338         /* work out how big the reply buffer could be */
339         for (i=0;i<io->smb2.out.num_changes;i++) {
340                 size += 12 + 3 + (1+strlen(io->smb2.out.changes[i].name.s)) * MAX_BYTES_PER_CHAR;
341         }
342
343         blob = data_blob_talloc(req, NULL, size);
344         if (size > 0 && !blob.data) {
345                 SMB2SRV_CHECK(NT_STATUS_NO_MEMORY);
346         }
347
348         p = blob.data;
349
350         /* construct the changes buffer */
351         for (i=0;i<io->smb2.out.num_changes;i++) {
352                 uint32_t ofs;
353                 ssize_t len;
354
355                 SIVAL(p, 4, io->smb2.out.changes[i].action);
356                 len = push_string(lp_iconv_convenience(global_loadparm), p + 12, io->smb2.out.changes[i].name.s, 
357                                   blob.length - (p+12 - blob.data), STR_UNICODE);
358                 SIVAL(p, 8, len);
359
360                 ofs = len + 12;
361
362                 if (ofs & 3) {
363                         int pad = 4 - (ofs & 3);
364                         memset(p+ofs, 0, pad);
365                         ofs += pad;
366                 }
367
368                 if (i == io->smb2.out.num_changes-1) {
369                         SIVAL(p, 0, 0);
370                 } else {
371                         SIVAL(p, 0, ofs);
372                 }
373
374                 p += ofs;
375         }
376
377         blob.length = p - blob.data;
378
379         SMB2SRV_CHECK(smb2_push_o16s32_blob(&req->out, 0x02, blob));
380
381         smb2srv_send_reply(req);
382 }
383
384 void smb2srv_notify_recv(struct smb2srv_request *req)
385 {
386         union smb_notify *io;
387
388         SMB2SRV_CHECK_BODY_SIZE(req, 0x20, false);
389         SMB2SRV_TALLOC_IO_PTR(io, union smb_notify);
390         SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_notify_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
391
392         io->smb2.level                  = RAW_NOTIFY_SMB2;
393         io->smb2.in.recursive           = SVAL(req->in.body, 0x02);
394         io->smb2.in.buffer_size         = IVAL(req->in.body, 0x04);
395         io->smb2.in.file.ntvfs          = smb2srv_pull_handle(req, req->in.body, 0x08);
396         io->smb2.in.completion_filter   = IVAL(req->in.body, 0x18);
397         io->smb2.in.unknown             = BVAL(req->in.body, 0x1C);
398
399         SMB2SRV_CHECK_FILE_HANDLE(io->smb2.in.file.ntvfs);
400         SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_notify(req->ntvfs, io));
401 }
402
403 void smb2srv_break_recv(struct smb2srv_request *req)
404 {
405         smb2srv_send_error(req, NT_STATUS_NOT_IMPLEMENTED);
406 }