s3:smb2_close: add add smbd_smb2_close_send/recv as wrapper
[metze/samba/wip.git] / source3 / smbd / smb2_close.c
1 /*
2    Unix SMB/CIFS implementation.
3    Core SMB2 server
4
5    Copyright (C) Stefan Metzmacher 2009
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 "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../lib/util/tevent_ntstatus.h"
26
27 static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
28                                 uint16_t in_flags,
29                                 uint64_t in_file_id_volatile,
30                                 uint16_t *out_flags,
31                                 NTTIME *out_creation_time,
32                                 NTTIME *out_last_access_time,
33                                 NTTIME *out_last_write_time,
34                                 NTTIME *out_change_time,
35                                 uint64_t *out_allocation_size,
36                                 uint64_t *out_end_of_file,
37                                 uint32_t *out_file_attributes);
38
39 static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
40                                                struct tevent_context *ev,
41                                                struct smbd_smb2_request *smb2req,
42                                                uint16_t in_flags,
43                                                uint64_t in_file_id_volatile);
44 static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
45                                      uint16_t *out_flags,
46                                      NTTIME *out_creation_time,
47                                      NTTIME *out_last_access_time,
48                                      NTTIME *out_last_write_time,
49                                      NTTIME *out_change_time,
50                                      uint64_t *out_allocation_size,
51                                      uint64_t *out_end_of_file,
52                                      uint32_t *out_file_attributes);
53
54 NTSTATUS smbd_smb2_request_process_close(struct smbd_smb2_request *req)
55 {
56         const uint8_t *inbody;
57         int i = req->current_idx;
58         DATA_BLOB outbody;
59         uint16_t in_flags;
60         uint64_t in_file_id_persistent;
61         uint64_t in_file_id_volatile;
62         uint16_t out_flags;
63         NTTIME out_creation_time;
64         NTTIME out_last_access_time;
65         NTTIME out_last_write_time;
66         NTTIME out_change_time;
67         uint64_t out_allocation_size;
68         uint64_t out_end_of_file;
69         uint32_t out_file_attributes;
70         NTSTATUS status;
71
72         status = smbd_smb2_request_verify_sizes(req, 0x18);
73         if (!NT_STATUS_IS_OK(status)) {
74                 return smbd_smb2_request_error(req, status);
75         }
76         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
77
78         outbody = data_blob_talloc(req->out.vector, NULL, 0x3C);
79         if (outbody.data == NULL) {
80                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
81         }
82
83         in_flags                = SVAL(inbody, 0x02);
84         in_file_id_persistent   = BVAL(inbody, 0x08);
85         in_file_id_volatile     = BVAL(inbody, 0x10);
86
87         if (req->compat_chain_fsp) {
88                 /* skip check */
89         } else if (in_file_id_persistent != in_file_id_volatile) {
90                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
91         }
92
93         status = smbd_smb2_close(req,
94                                 in_flags,
95                                 in_file_id_volatile,
96                                 &out_flags,
97                                 &out_creation_time,
98                                 &out_last_access_time,
99                                 &out_last_write_time,
100                                 &out_change_time,
101                                 &out_allocation_size,
102                                 &out_end_of_file,
103                                 &out_file_attributes);
104         if (!NT_STATUS_IS_OK(status)) {
105                 return smbd_smb2_request_error(req, status);
106         }
107
108         SSVAL(outbody.data, 0x00, 0x3C);        /* struct size */
109         SSVAL(outbody.data, 0x02, out_flags);
110         SIVAL(outbody.data, 0x04, 0);           /* reserved */
111         SBVAL(outbody.data, 0x08, out_creation_time);
112         SBVAL(outbody.data, 0x10, out_last_access_time);
113         SBVAL(outbody.data, 0x18, out_last_write_time);
114         SBVAL(outbody.data, 0x20, out_change_time);
115         SBVAL(outbody.data, 0x28, out_allocation_size);
116         SBVAL(outbody.data, 0x30, out_end_of_file);
117         SIVAL(outbody.data, 0x38, out_file_attributes);
118
119         return smbd_smb2_request_done(req, outbody, NULL);
120 }
121
122 static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
123                                 uint16_t in_flags,
124                                 uint64_t in_file_id_volatile,
125                                 uint16_t *out_flags,
126                                 NTTIME *out_creation_time,
127                                 NTTIME *out_last_access_time,
128                                 NTTIME *out_last_write_time,
129                                 NTTIME *out_change_time,
130                                 uint64_t *out_allocation_size,
131                                 uint64_t *out_end_of_file,
132                                 uint32_t *out_file_attributes)
133 {
134         NTSTATUS status;
135         struct smb_request *smbreq;
136         connection_struct *conn = req->tcon->compat_conn;
137         files_struct *fsp;
138         struct smb_filename *smb_fname = NULL;
139         struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
140         uint64_t allocation_size = 0;
141         uint64_t file_size = 0;
142         uint32_t dos_attrs = 0;
143         uint16_t flags = 0;
144         bool posix_open = false;
145
146         ZERO_STRUCT(create_date_ts);
147         ZERO_STRUCT(adate_ts);
148         ZERO_STRUCT(mdate_ts);
149         ZERO_STRUCT(cdate_ts);
150
151         *out_flags = 0;
152         *out_creation_time = 0;
153         *out_last_access_time = 0;
154         *out_last_write_time = 0;
155         *out_change_time = 0;
156         *out_allocation_size = 0;
157         *out_end_of_file = 0;
158         *out_file_attributes = 0;
159
160         DEBUG(10,("smbd_smb2_close: file_id[0x%016llX]\n",
161                   (unsigned long long)in_file_id_volatile));
162
163         smbreq = smbd_smb2_fake_smb_request(req);
164         if (smbreq == NULL) {
165                 return NT_STATUS_NO_MEMORY;
166         }
167
168         fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile);
169         if (fsp == NULL) {
170                 return NT_STATUS_FILE_CLOSED;
171         }
172         if (conn != fsp->conn) {
173                 return NT_STATUS_FILE_CLOSED;
174         }
175         if (req->session->vuid != fsp->vuid) {
176                 return NT_STATUS_FILE_CLOSED;
177         }
178
179         posix_open = fsp->posix_open;
180         status = copy_smb_filename(talloc_tos(),
181                                 fsp->fsp_name,
182                                 &smb_fname);
183         if (!NT_STATUS_IS_OK(status)) {
184                 return status;
185         }
186
187         status = close_file(smbreq, fsp, NORMAL_CLOSE);
188         if (!NT_STATUS_IS_OK(status)) {
189                 DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
190                          fsp_str_dbg(fsp), nt_errstr(status)));
191                 return status;
192         }
193
194         if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
195                 int ret;
196                 if (posix_open) {
197                         ret = SMB_VFS_LSTAT(conn, smb_fname);
198                 } else {
199                         ret = SMB_VFS_STAT(conn, smb_fname);
200                 }
201                 if (ret == 0) {
202                         flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
203                         dos_attrs = dos_mode(conn, smb_fname);
204                         mdate_ts = smb_fname->st.st_ex_mtime;
205                         adate_ts = smb_fname->st.st_ex_atime;
206                         create_date_ts = get_create_timespec(conn, NULL, smb_fname);
207                         cdate_ts = get_change_timespec(conn, NULL, smb_fname);
208
209                         if (lp_dos_filetime_resolution(SNUM(conn))) {
210                                 dos_filetime_timespec(&create_date_ts);
211                                 dos_filetime_timespec(&mdate_ts);
212                                 dos_filetime_timespec(&adate_ts);
213                                 dos_filetime_timespec(&cdate_ts);
214                         }
215                         if (!(dos_attrs & FILE_ATTRIBUTE_DIRECTORY)) {
216                                 file_size = get_file_size_stat(&smb_fname->st);
217                         }
218
219                         allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
220                 }
221         }
222
223         *out_flags = flags;
224
225         round_timespec(conn->ts_res, &create_date_ts);
226         unix_timespec_to_nt_time(out_creation_time, create_date_ts);
227
228         round_timespec(conn->ts_res, &adate_ts);
229         unix_timespec_to_nt_time(out_last_access_time, adate_ts);
230
231         round_timespec(conn->ts_res, &mdate_ts);
232         unix_timespec_to_nt_time(out_last_write_time, mdate_ts);
233
234         round_timespec(conn->ts_res, &cdate_ts);
235         unix_timespec_to_nt_time(out_change_time, cdate_ts);
236
237         *out_allocation_size = allocation_size;
238         *out_end_of_file = file_size;
239         *out_file_attributes = dos_attrs;
240
241         return NT_STATUS_OK;
242 }
243
244 struct smbd_smb2_close_state {
245         uint16_t in_flags;
246         uint64_t in_file_id_volatile;
247         uint16_t out_flags;
248         NTTIME out_creation_time;
249         NTTIME out_last_access_time;
250         NTTIME out_last_write_time;
251         NTTIME out_change_time;
252         uint64_t out_allocation_size;
253         uint64_t out_end_of_file;
254         uint32_t out_file_attributes;
255 };
256
257 static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
258                                                struct tevent_context *ev,
259                                                struct smbd_smb2_request *smb2req,
260                                                uint16_t in_flags,
261                                                uint64_t in_file_id_volatile)
262 {
263         struct tevent_req *req;
264         struct smbd_smb2_close_state *state;
265         NTSTATUS status;
266
267         req = tevent_req_create(mem_ctx, &state,
268                                 struct smbd_smb2_close_state);
269         if (req == NULL) {
270                 return NULL;
271         }
272         state->in_flags = in_flags;
273         state->in_file_id_volatile = in_file_id_volatile;
274
275         status = smbd_smb2_close(smb2req,
276                                  state->in_flags,
277                                  state->in_file_id_volatile,
278                                  &state->out_flags,
279                                  &state->out_creation_time,
280                                  &state->out_last_access_time,
281                                  &state->out_last_write_time,
282                                  &state->out_change_time,
283                                  &state->out_allocation_size,
284                                  &state->out_end_of_file,
285                                  &state->out_file_attributes);
286         if (tevent_req_nterror(req, status)) {
287                 return tevent_req_post(req, ev);
288         }
289
290         tevent_req_done(req);
291         return tevent_req_post(req, ev);
292 }
293
294 static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
295                                      uint16_t *out_flags,
296                                      NTTIME *out_creation_time,
297                                      NTTIME *out_last_access_time,
298                                      NTTIME *out_last_write_time,
299                                      NTTIME *out_change_time,
300                                      uint64_t *out_allocation_size,
301                                      uint64_t *out_end_of_file,
302                                      uint32_t *out_file_attributes)
303 {
304         struct smbd_smb2_close_state *state =
305                 tevent_req_data(req,
306                 struct smbd_smb2_close_state);
307         NTSTATUS status;
308
309         if (tevent_req_is_nterror(req, &status)) {
310                 tevent_req_received(req);
311                 return status;
312         }
313
314         *out_flags = state->out_flags;
315         *out_creation_time = state->out_creation_time;
316         *out_last_access_time = state->out_last_access_time;
317         *out_last_write_time = state->out_last_write_time;
318         *out_change_time = state->out_change_time;
319         *out_allocation_size = state->out_allocation_size;
320         *out_end_of_file = state->out_end_of_file;
321         *out_file_attributes = state->out_file_attributes;
322
323         tevent_req_received(req);
324         return NT_STATUS_OK;
325 }