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