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