LCOV - code coverage report
Current view: top level - source3/smbd - smb2_flush.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 66 93 71.0 %
Date: 2021-08-25 13:27:56 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          76 : NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req)
      39             : {
      40             :         NTSTATUS status;
      41             :         const uint8_t *inbody;
      42             :         uint64_t in_file_id_persistent;
      43             :         uint64_t in_file_id_volatile;
      44             :         struct files_struct *in_fsp;
      45             :         struct tevent_req *subreq;
      46             : 
      47          76 :         status = smbd_smb2_request_verify_sizes(req, 0x18);
      48          76 :         if (!NT_STATUS_IS_OK(status)) {
      49           0 :                 return smbd_smb2_request_error(req, status);
      50             :         }
      51          76 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      52             : 
      53          76 :         in_file_id_persistent   = BVAL(inbody, 0x08);
      54          76 :         in_file_id_volatile     = BVAL(inbody, 0x10);
      55             : 
      56          76 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
      57          76 :         if (in_fsp == NULL) {
      58           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
      59             :         }
      60             : 
      61          76 :         subreq = smbd_smb2_flush_send(req, req->sconn->ev_ctx,
      62             :                                       req, in_fsp);
      63          76 :         if (subreq == NULL) {
      64           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
      65             :         }
      66          76 :         tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req);
      67             : 
      68          76 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
      69             : }
      70             : 
      71          76 : static void smbd_smb2_request_flush_done(struct tevent_req *subreq)
      72             : {
      73          76 :         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
      74             :                                         struct smbd_smb2_request);
      75             :         DATA_BLOB outbody;
      76             :         NTSTATUS status;
      77             :         NTSTATUS error; /* transport error */
      78             : 
      79          76 :         status = smbd_smb2_flush_recv(subreq);
      80          76 :         TALLOC_FREE(subreq);
      81          76 :         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           0 :                         return;
      87             :                 }
      88          16 :                 return;
      89             :         }
      90             : 
      91          60 :         outbody = smbd_smb2_generate_outbody(req, 0x04);
      92          60 :         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          60 :         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
     103          60 :         SSVAL(outbody.data, 0x02, 0);           /* reserved */
     104             : 
     105          60 :         error = smbd_smb2_request_done(req, outbody, NULL);
     106          60 :         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          76 : 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             :         struct tevent_req *req;
     126             :         struct tevent_req *subreq;
     127             :         struct smbd_smb2_flush_state *state;
     128             :         struct smb_request *smbreq;
     129             : 
     130          76 :         req = tevent_req_create(mem_ctx, &state,
     131             :                                 struct smbd_smb2_flush_state);
     132          76 :         if (req == NULL) {
     133           0 :                 return NULL;
     134             :         }
     135          76 :         state->smb2req = smb2req;
     136          76 :         state->fsp = fsp;
     137             : 
     138          76 :         DEBUG(10,("smbd_smb2_flush: %s - %s\n",
     139             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     140             : 
     141          76 :         smbreq = smbd_smb2_fake_smb_request(smb2req);
     142          76 :         if (tevent_req_nomem(smbreq, req)) {
     143           0 :                 return tevent_req_post(req, ev);
     144             :         }
     145             : 
     146          76 :         if (IS_IPC(smbreq->conn)) {
     147           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
     148           0 :                 return tevent_req_post(req, ev);
     149             :         }
     150             : 
     151          76 :         if (!CHECK_WRITE(fsp)) {
     152          32 :                 bool allow_dir_flush = false;
     153          32 :                 uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
     154             : 
     155          32 :                 if (!fsp->fsp_flags.is_directory) {
     156           0 :                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     157           0 :                         return tevent_req_post(req, ev);
     158             :                 }
     159             : 
     160             :                 /*
     161             :                  * Directories are not writable in the conventional
     162             :                  * sense, but if opened with *either*
     163             :                  * FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
     164             :                  * they can be flushed.
     165             :                  */
     166             : 
     167          32 :                 if ((fsp->access_mask & flush_access) != 0) {
     168          16 :                         allow_dir_flush = true;
     169             :                 }
     170             : 
     171          32 :                 if (allow_dir_flush == false) {
     172          16 :                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     173          16 :                         return tevent_req_post(req, ev);
     174             :                 }
     175             :         }
     176             : 
     177          60 :         if (fsp_get_io_fd(fsp) == -1) {
     178           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
     179           0 :                 return tevent_req_post(req, ev);
     180             :         }
     181             : 
     182          60 :         if (!lp_strict_sync(SNUM(smbreq->conn))) {
     183             :                 /*
     184             :                  * No strict sync. Don't really do
     185             :                  * anything here.
     186             :                  */
     187           0 :                 tevent_req_done(req);
     188           0 :                 return tevent_req_post(req, ev);
     189             :         }
     190             : 
     191          60 :         subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
     192          60 :         if (tevent_req_nomem(subreq, req)) {
     193           0 :                 return tevent_req_post(req, ev);
     194             :         }
     195             : 
     196          60 :         tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
     197             : 
     198             :         /* Ensure any close request knows about this outstanding IO. */
     199          60 :         if (!aio_add_req_to_fsp(fsp, req)) {
     200           0 :                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
     201           0 :                 return tevent_req_post(req, ev);
     202             :         }
     203             : 
     204          60 :         return req;
     205             : 
     206             : }
     207             : 
     208          60 : static void smbd_smb2_flush_done(struct tevent_req *subreq)
     209             : {
     210          60 :         struct tevent_req *req = tevent_req_callback_data(
     211             :                 subreq, struct tevent_req);
     212          60 :         struct smbd_smb2_flush_state *state = tevent_req_data(
     213             :                 req, struct smbd_smb2_flush_state);
     214             :         int ret;
     215             :         struct vfs_aio_state vfs_aio_state;
     216             : 
     217          60 :         ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
     218          60 :         TALLOC_FREE(subreq);
     219          60 :         if (ret == -1) {
     220           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
     221           0 :                 return;
     222             :         }
     223          60 :         if (state->fsp->fsp_flags.modified) {
     224          36 :                 trigger_write_time_update_immediate(state->fsp);
     225             :         }
     226          60 :         tevent_req_done(req);
     227             : }
     228             : 
     229          76 : static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
     230             : {
     231             :         NTSTATUS status;
     232             : 
     233          76 :         if (tevent_req_is_nterror(req, &status)) {
     234          16 :                 tevent_req_received(req);
     235          16 :                 return status;
     236             :         }
     237             : 
     238          60 :         tevent_req_received(req);
     239          60 :         return NT_STATUS_OK;
     240             : }

Generated by: LCOV version 1.13