LCOV - code coverage report
Current view: top level - source3/smbd - smb2_flush.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 73 115 63.5 %
Date: 2023-11-21 12:31:41 Functions: 5 5 100.0 %

          Line data    Source code
       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             : #include "libcli/security/security.h"
      27             : 
      28             : #undef DBGC_CLASS
      29             : #define DBGC_CLASS DBGC_SMB2
      30             : 
      31             : static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
      32             :                                                struct tevent_context *ev,
      33             :                                                struct smbd_smb2_request *smb2req,
      34             :                                                struct files_struct *fsp);
      35             : static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req);
      36             : 
      37             : static void smbd_smb2_request_flush_done(struct tevent_req *subreq);
      38          88 : NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req)
      39             : {
      40           0 :         NTSTATUS status;
      41           0 :         const uint8_t *inbody;
      42           0 :         uint64_t in_file_id_persistent;
      43           0 :         uint64_t in_file_id_volatile;
      44           0 :         struct files_struct *in_fsp;
      45           0 :         struct tevent_req *subreq;
      46             : 
      47          88 :         status = smbd_smb2_request_verify_sizes(req, 0x18);
      48          88 :         if (!NT_STATUS_IS_OK(status)) {
      49           0 :                 return smbd_smb2_request_error(req, status);
      50             :         }
      51          88 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      52             : 
      53          88 :         in_file_id_persistent   = BVAL(inbody, 0x08);
      54          88 :         in_file_id_volatile     = BVAL(inbody, 0x10);
      55             : 
      56          88 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
      57          88 :         if (in_fsp == NULL) {
      58           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
      59             :         }
      60             : 
      61          88 :         subreq = smbd_smb2_flush_send(req, req->sconn->ev_ctx,
      62             :                                       req, in_fsp);
      63          88 :         if (subreq == NULL) {
      64           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
      65             :         }
      66          88 :         tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req);
      67             : 
      68          88 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
      69             : }
      70             : 
      71          88 : static void smbd_smb2_request_flush_done(struct tevent_req *subreq)
      72             : {
      73          88 :         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
      74             :                                         struct smbd_smb2_request);
      75           0 :         DATA_BLOB outbody;
      76           0 :         NTSTATUS status;
      77           0 :         NTSTATUS error; /* transport error */
      78             : 
      79          88 :         status = smbd_smb2_flush_recv(subreq);
      80          88 :         TALLOC_FREE(subreq);
      81          88 :         if (!NT_STATUS_IS_OK(status)) {
      82          16 :                 error = smbd_smb2_request_error(req, status);
      83          16 :                 if (!NT_STATUS_IS_OK(error)) {
      84           0 :                         smbd_server_connection_terminate(req->xconn,
      85             :                                                          nt_errstr(error));
      86          16 :                         return;
      87             :                 }
      88          16 :                 return;
      89             :         }
      90             : 
      91          72 :         outbody = smbd_smb2_generate_outbody(req, 0x04);
      92          72 :         if (outbody.data == NULL) {
      93           0 :                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
      94           0 :                 if (!NT_STATUS_IS_OK(error)) {
      95           0 :                         smbd_server_connection_terminate(req->xconn,
      96             :                                                          nt_errstr(error));
      97           0 :                         return;
      98             :                 }
      99           0 :                 return;
     100             :         }
     101             : 
     102          72 :         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
     103          72 :         SSVAL(outbody.data, 0x02, 0);           /* reserved */
     104             : 
     105          72 :         error = smbd_smb2_request_done(req, outbody, NULL);
     106          72 :         if (!NT_STATUS_IS_OK(error)) {
     107           0 :                 smbd_server_connection_terminate(req->xconn,
     108             :                                                  nt_errstr(error));
     109           0 :                 return;
     110             :         }
     111             : }
     112             : 
     113             : struct smbd_smb2_flush_state {
     114             :         struct smbd_smb2_request *smb2req;
     115             :         struct files_struct *fsp;
     116             : };
     117             : 
     118             : static void smbd_smb2_flush_done(struct tevent_req *subreq);
     119             : 
     120          88 : static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
     121             :                                                struct tevent_context *ev,
     122             :                                                struct smbd_smb2_request *smb2req,
     123             :                                                struct files_struct *fsp)
     124             : {
     125           0 :         struct tevent_req *req;
     126           0 :         struct tevent_req *subreq;
     127           0 :         struct smbd_smb2_flush_state *state;
     128           0 :         struct smb_request *smbreq;
     129          88 :         bool is_compound = false;
     130          88 :         bool is_last_in_compound = false;
     131             : 
     132          88 :         req = tevent_req_create(mem_ctx, &state,
     133             :                                 struct smbd_smb2_flush_state);
     134          88 :         if (req == NULL) {
     135           0 :                 return NULL;
     136             :         }
     137          88 :         state->smb2req = smb2req;
     138          88 :         state->fsp = fsp;
     139             : 
     140          88 :         DEBUG(10,("smbd_smb2_flush: %s - %s\n",
     141             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     142             : 
     143          88 :         smbreq = smbd_smb2_fake_smb_request(smb2req, fsp);
     144          88 :         if (tevent_req_nomem(smbreq, req)) {
     145           0 :                 return tevent_req_post(req, ev);
     146             :         }
     147             : 
     148          88 :         if (IS_IPC(smbreq->conn)) {
     149           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
     150           0 :                 return tevent_req_post(req, ev);
     151             :         }
     152             : 
     153          88 :         if (!CHECK_WRITE(fsp)) {
     154          32 :                 bool allow_dir_flush = false;
     155          32 :                 uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
     156             : 
     157          32 :                 if (!fsp->fsp_flags.is_directory) {
     158           0 :                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     159           0 :                         return tevent_req_post(req, ev);
     160             :                 }
     161             : 
     162             :                 /*
     163             :                  * Directories are not writable in the conventional
     164             :                  * sense, but if opened with *either*
     165             :                  * FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
     166             :                  * they can be flushed.
     167             :                  */
     168             : 
     169          32 :                 if ((fsp->access_mask & flush_access) != 0) {
     170          16 :                         allow_dir_flush = true;
     171             :                 }
     172             : 
     173          32 :                 if (allow_dir_flush == false) {
     174          16 :                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     175          16 :                         return tevent_req_post(req, ev);
     176             :                 }
     177             :         }
     178             : 
     179          72 :         if (fsp_get_io_fd(fsp) == -1) {
     180           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
     181           0 :                 return tevent_req_post(req, ev);
     182             :         }
     183             : 
     184          72 :         if (!lp_strict_sync(SNUM(smbreq->conn))) {
     185             :                 /*
     186             :                  * No strict sync. Don't really do
     187             :                  * anything here.
     188             :                  */
     189           0 :                 tevent_req_done(req);
     190           0 :                 return tevent_req_post(req, ev);
     191             :         }
     192             : 
     193          72 :         subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
     194          72 :         if (tevent_req_nomem(subreq, req)) {
     195           0 :                 return tevent_req_post(req, ev);
     196             :         }
     197             : 
     198          72 :         tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
     199             : 
     200          72 :         is_compound = smbd_smb2_is_compound(smb2req);
     201          72 :         is_last_in_compound = smbd_smb2_is_last_in_compound(smb2req);
     202             : 
     203          72 :         if (is_compound && !is_last_in_compound) {
     204             :                 /*
     205             :                  * Can't go async if we're not the
     206             :                  * last request in a compound request.
     207             :                  * Cause this request to complete synchronously.
     208             :                  */
     209           4 :                 smb2_request_set_async_internal(state->smb2req, true);
     210             :         }
     211             : 
     212             :         /* Ensure any close request knows about this outstanding IO. */
     213          72 :         if (!aio_add_req_to_fsp(fsp, req)) {
     214           0 :                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
     215           0 :                 return tevent_req_post(req, ev);
     216             :         }
     217             : 
     218          72 :         return req;
     219             : 
     220             : }
     221             : 
     222          72 : static void smbd_smb2_flush_done(struct tevent_req *subreq)
     223             : {
     224          72 :         struct tevent_req *req = tevent_req_callback_data(
     225             :                 subreq, struct tevent_req);
     226          72 :         struct smbd_smb2_flush_state *state = tevent_req_data(
     227             :                 req, struct smbd_smb2_flush_state);
     228           0 :         int ret;
     229           0 :         struct vfs_aio_state vfs_aio_state;
     230             : 
     231          72 :         ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
     232          72 :         TALLOC_FREE(subreq);
     233          72 :         if (ret == -1) {
     234           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
     235           0 :                 return;
     236             :         }
     237          72 :         if (state->fsp->fsp_flags.modified) {
     238          42 :                 trigger_write_time_update_immediate(state->fsp);
     239             :         }
     240          72 :         tevent_req_done(req);
     241             : }
     242             : 
     243          88 : static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
     244             : {
     245           0 :         NTSTATUS status;
     246             : 
     247          88 :         if (tevent_req_is_nterror(req, &status)) {
     248          16 :                 tevent_req_received(req);
     249          16 :                 return status;
     250             :         }
     251             : 
     252          72 :         tevent_req_received(req);
     253          72 :         return NT_STATUS_OK;
     254             : }

Generated by: LCOV version 1.14