LCOV - code coverage report
Current view: top level - source3/smbd - smb2_flush.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 74 118 62.7 %
Date: 2024-04-21 15:09:00 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           0 :         NTSTATUS status;
     132             : 
     133          88 :         req = tevent_req_create(mem_ctx, &state,
     134             :                                 struct smbd_smb2_flush_state);
     135          88 :         if (req == NULL) {
     136           0 :                 return NULL;
     137             :         }
     138          88 :         state->smb2req = smb2req;
     139          88 :         state->fsp = fsp;
     140             : 
     141          88 :         DEBUG(10,("smbd_smb2_flush: %s - %s\n",
     142             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     143             : 
     144          88 :         smbreq = smbd_smb2_fake_smb_request(smb2req, fsp);
     145          88 :         if (tevent_req_nomem(smbreq, req)) {
     146           0 :                 return tevent_req_post(req, ev);
     147             :         }
     148             : 
     149          88 :         if (IS_IPC(smbreq->conn)) {
     150           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
     151           0 :                 return tevent_req_post(req, ev);
     152             :         }
     153             : 
     154          88 :         status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
     155          88 :         if (!NT_STATUS_IS_OK(status)) {
     156          16 :                 bool allow_dir_flush = false;
     157          16 :                 uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
     158             : 
     159          16 :                 if (!fsp->fsp_flags.is_directory) {
     160           0 :                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     161           0 :                         return tevent_req_post(req, ev);
     162             :                 }
     163             : 
     164             :                 /*
     165             :                  * Directories are not writable in the conventional
     166             :                  * sense, but if opened with *either*
     167             :                  * FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
     168             :                  * they can be flushed.
     169             :                  */
     170             : 
     171          16 :                 status = check_any_access_fsp(fsp, flush_access);
     172          16 :                 if (NT_STATUS_IS_OK(status)) {
     173           0 :                         allow_dir_flush = true;
     174             :                 }
     175             : 
     176          16 :                 if (allow_dir_flush == false) {
     177          16 :                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     178          16 :                         return tevent_req_post(req, ev);
     179             :                 }
     180             :         }
     181             : 
     182          72 :         if (fsp_get_io_fd(fsp) == -1) {
     183           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
     184           0 :                 return tevent_req_post(req, ev);
     185             :         }
     186             : 
     187          72 :         if (!lp_strict_sync(SNUM(smbreq->conn))) {
     188             :                 /*
     189             :                  * No strict sync. Don't really do
     190             :                  * anything here.
     191             :                  */
     192           0 :                 tevent_req_done(req);
     193           0 :                 return tevent_req_post(req, ev);
     194             :         }
     195             : 
     196          72 :         subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
     197          72 :         if (tevent_req_nomem(subreq, req)) {
     198           0 :                 return tevent_req_post(req, ev);
     199             :         }
     200             : 
     201          72 :         tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
     202             : 
     203          72 :         is_compound = smbd_smb2_is_compound(smb2req);
     204          72 :         is_last_in_compound = smbd_smb2_is_last_in_compound(smb2req);
     205             : 
     206          72 :         if (is_compound && !is_last_in_compound) {
     207             :                 /*
     208             :                  * Can't go async if we're not the
     209             :                  * last request in a compound request.
     210             :                  * Cause this request to complete synchronously.
     211             :                  */
     212           4 :                 smb2_request_set_async_internal(state->smb2req, true);
     213             :         }
     214             : 
     215             :         /* Ensure any close request knows about this outstanding IO. */
     216          72 :         if (!aio_add_req_to_fsp(fsp, req)) {
     217           0 :                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
     218           0 :                 return tevent_req_post(req, ev);
     219             :         }
     220             : 
     221          72 :         return req;
     222             : 
     223             : }
     224             : 
     225          72 : static void smbd_smb2_flush_done(struct tevent_req *subreq)
     226             : {
     227          72 :         struct tevent_req *req = tevent_req_callback_data(
     228             :                 subreq, struct tevent_req);
     229          72 :         struct smbd_smb2_flush_state *state = tevent_req_data(
     230             :                 req, struct smbd_smb2_flush_state);
     231           0 :         int ret;
     232           0 :         struct vfs_aio_state vfs_aio_state;
     233             : 
     234          72 :         ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
     235          72 :         TALLOC_FREE(subreq);
     236          72 :         if (ret == -1) {
     237           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
     238           0 :                 return;
     239             :         }
     240          72 :         if (state->fsp->fsp_flags.modified) {
     241          42 :                 trigger_write_time_update_immediate(state->fsp);
     242             :         }
     243          72 :         tevent_req_done(req);
     244             : }
     245             : 
     246          88 : static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
     247             : {
     248           0 :         NTSTATUS status;
     249             : 
     250          88 :         if (tevent_req_is_nterror(req, &status)) {
     251          16 :                 tevent_req_received(req);
     252          16 :                 return status;
     253             :         }
     254             : 
     255          72 :         tevent_req_received(req);
     256          72 :         return NT_STATUS_OK;
     257             : }

Generated by: LCOV version 1.14