s3:smb2_flush: outbody only needs 4 bytes
[samba.git] / source3 / smbd / smb2_flush.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 struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
28                                                struct tevent_context *ev,
29                                                struct smbd_smb2_request *smb2req,
30                                                uint64_t in_file_id_volatile);
31 static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req);
32
33 static void smbd_smb2_request_flush_done(struct tevent_req *subreq);
34 NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req)
35 {
36         NTSTATUS status;
37         const uint8_t *inbody;
38         int i = req->current_idx;
39         uint64_t in_file_id_persistent;
40         uint64_t in_file_id_volatile;
41         struct tevent_req *subreq;
42
43         status = smbd_smb2_request_verify_sizes(req, 0x18);
44         if (!NT_STATUS_IS_OK(status)) {
45                 return smbd_smb2_request_error(req, status);
46         }
47         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
48
49         in_file_id_persistent   = BVAL(inbody, 0x08);
50         in_file_id_volatile     = BVAL(inbody, 0x10);
51
52         if (req->compat_chain_fsp) {
53                 /* skip check */
54         } else if (in_file_id_persistent != in_file_id_volatile) {
55                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
56         }
57
58         subreq = smbd_smb2_flush_send(req,
59                                       req->sconn->smb2.event_ctx,
60                                       req,
61                                       in_file_id_volatile);
62         if (subreq == NULL) {
63                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
64         }
65         tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req);
66
67         return smbd_smb2_request_pending_queue(req, subreq);
68 }
69
70 static void smbd_smb2_request_flush_done(struct tevent_req *subreq)
71 {
72         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
73                                         struct smbd_smb2_request);
74         DATA_BLOB outbody;
75         NTSTATUS status;
76         NTSTATUS error; /* transport error */
77
78         status = smbd_smb2_flush_recv(subreq);
79         TALLOC_FREE(subreq);
80         if (!NT_STATUS_IS_OK(status)) {
81                 error = smbd_smb2_request_error(req, status);
82                 if (!NT_STATUS_IS_OK(error)) {
83                         smbd_server_connection_terminate(req->sconn,
84                                                          nt_errstr(error));
85                         return;
86                 }
87                 return;
88         }
89
90         outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
91         if (outbody.data == NULL) {
92                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
93                 if (!NT_STATUS_IS_OK(error)) {
94                         smbd_server_connection_terminate(req->sconn,
95                                                          nt_errstr(error));
96                         return;
97                 }
98                 return;
99         }
100
101         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
102         SSVAL(outbody.data, 0x02, 0);           /* reserved */
103
104         error = smbd_smb2_request_done(req, outbody, NULL);
105         if (!NT_STATUS_IS_OK(error)) {
106                 smbd_server_connection_terminate(req->sconn,
107                                                  nt_errstr(error));
108                 return;
109         }
110 }
111
112 struct smbd_smb2_flush_state {
113         struct smbd_smb2_request *smb2req;
114 };
115
116 static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
117                                                struct tevent_context *ev,
118                                                struct smbd_smb2_request *smb2req,
119                                                uint64_t in_file_id_volatile)
120 {
121         struct tevent_req *req;
122         struct smbd_smb2_flush_state *state;
123         NTSTATUS status;
124         struct smb_request *smbreq;
125         files_struct *fsp;
126
127         req = tevent_req_create(mem_ctx, &state,
128                                 struct smbd_smb2_flush_state);
129         if (req == NULL) {
130                 return NULL;
131         }
132         state->smb2req = smb2req;
133
134         DEBUG(10,("smbd_smb2_flush: file_id[0x%016llX]\n",
135                   (unsigned long long)in_file_id_volatile));
136
137         smbreq = smbd_smb2_fake_smb_request(smb2req);
138         if (tevent_req_nomem(smbreq, req)) {
139                 return tevent_req_post(req, ev);
140         }
141
142         if (IS_IPC(smbreq->conn)) {
143                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
144                 return tevent_req_post(req, ev);
145         }
146
147         fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile);
148         if (fsp == NULL) {
149                 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
150                 return tevent_req_post(req, ev);
151         }
152         if (smbreq->conn != fsp->conn) {
153                 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
154                 return tevent_req_post(req, ev);
155         }
156         if (smb2req->session->vuid != fsp->vuid) {
157                 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
158                 return tevent_req_post(req, ev);
159         }
160
161         if (!CHECK_WRITE(fsp)) {
162                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
163                 return tevent_req_post(req, ev);
164         }
165
166         status = sync_file(smbreq->conn, fsp, true);
167         if (!NT_STATUS_IS_OK(status)) {
168                 DEBUG(5,("smbd_smb2_flush: sync_file for %s returned %s\n",
169                          fsp_str_dbg(fsp), nt_errstr(status)));
170                 tevent_req_nterror(req, status);
171                 return tevent_req_post(req, ev);
172         }
173
174         tevent_req_done(req);
175         return tevent_req_post(req, ev);
176 }
177
178 static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
179 {
180         NTSTATUS status;
181
182         if (tevent_req_is_nterror(req, &status)) {
183                 tevent_req_received(req);
184                 return status;
185         }
186
187         tevent_req_received(req);
188         return NT_STATUS_OK;
189 }