LCOV - code coverage report
Current view: top level - source3/smbd - smb2_close.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 107 177 60.5 %
Date: 2024-06-13 04:01:37 Functions: 5 7 71.4 %

          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             : 
      27             : #undef DBGC_CLASS
      28             : #define DBGC_CLASS DBGC_SMB2
      29             : 
      30             : static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
      31             :                                                struct tevent_context *ev,
      32             :                                                struct smbd_smb2_request *smb2req,
      33             :                                                struct files_struct *in_fsp,
      34             :                                                uint16_t in_flags);
      35             : static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
      36             :                                      uint16_t *out_flags,
      37             :                                      struct timespec *out_creation_ts,
      38             :                                      struct timespec *out_last_access_ts,
      39             :                                      struct timespec *out_last_write_ts,
      40             :                                      struct timespec *out_change_ts,
      41             :                                      uint64_t *out_allocation_size,
      42             :                                      uint64_t *out_end_of_file,
      43             :                                      uint32_t *out_file_attributes);
      44             : 
      45             : static void smbd_smb2_request_close_done(struct tevent_req *subreq);
      46             : 
      47       15148 : NTSTATUS smbd_smb2_request_process_close(struct smbd_smb2_request *req)
      48             : {
      49             :         const uint8_t *inbody;
      50             :         uint16_t in_flags;
      51             :         uint64_t in_file_id_persistent;
      52             :         uint64_t in_file_id_volatile;
      53             :         struct files_struct *in_fsp;
      54             :         NTSTATUS status;
      55             :         struct tevent_req *subreq;
      56             : 
      57       15148 :         status = smbd_smb2_request_verify_sizes(req, 0x18);
      58       15148 :         if (!NT_STATUS_IS_OK(status)) {
      59           0 :                 return smbd_smb2_request_error(req, status);
      60             :         }
      61       15148 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      62             : 
      63       15148 :         in_flags                = SVAL(inbody, 0x02);
      64       15148 :         in_file_id_persistent   = BVAL(inbody, 0x08);
      65       15148 :         in_file_id_volatile     = BVAL(inbody, 0x10);
      66             : 
      67       15148 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
      68       15148 :         if (in_fsp == NULL) {
      69           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
      70             :         }
      71             : 
      72       15148 :         subreq = smbd_smb2_close_send(req, req->sconn->ev_ctx,
      73             :                                       req, in_fsp, in_flags);
      74       15148 :         if (subreq == NULL) {
      75           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
      76             :         }
      77       15148 :         tevent_req_set_callback(subreq, smbd_smb2_request_close_done, req);
      78             : 
      79       15148 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
      80             : }
      81             : 
      82       15148 : static void smbd_smb2_request_close_done(struct tevent_req *subreq)
      83             : {
      84       13142 :         struct smbd_smb2_request *req =
      85       15148 :                 tevent_req_callback_data(subreq,
      86             :                 struct smbd_smb2_request);
      87             :         DATA_BLOB outbody;
      88       15148 :         uint16_t out_flags = 0;
      89       15148 :         connection_struct *conn = req->tcon->compat;
      90       15148 :         struct timespec out_creation_ts = { 0, };
      91       15148 :         struct timespec out_last_access_ts = { 0, };
      92       15148 :         struct timespec out_last_write_ts = { 0, };
      93       15148 :         struct timespec out_change_ts = { 0, };
      94       15148 :         uint64_t out_allocation_size = 0;
      95       15148 :         uint64_t out_end_of_file = 0;
      96       15148 :         uint32_t out_file_attributes = 0;
      97             :         NTSTATUS status;
      98             :         NTSTATUS error;
      99             : 
     100       15148 :         status = smbd_smb2_close_recv(subreq,
     101             :                                       &out_flags,
     102             :                                       &out_creation_ts,
     103             :                                       &out_last_access_ts,
     104             :                                       &out_last_write_ts,
     105             :                                       &out_change_ts,
     106             :                                       &out_allocation_size,
     107             :                                       &out_end_of_file,
     108             :                                       &out_file_attributes);
     109       15148 :         TALLOC_FREE(subreq);
     110       15148 :         if (!NT_STATUS_IS_OK(status)) {
     111           0 :                 error = smbd_smb2_request_error(req, status);
     112           0 :                 if (!NT_STATUS_IS_OK(error)) {
     113           0 :                         smbd_server_connection_terminate(req->xconn,
     114             :                                                          nt_errstr(error));
     115           0 :                         return;
     116             :                 }
     117           0 :                 return;
     118             :         }
     119             : 
     120       15148 :         outbody = smbd_smb2_generate_outbody(req, 0x3C);
     121       15148 :         if (outbody.data == NULL) {
     122           0 :                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     123           0 :                 if (!NT_STATUS_IS_OK(error)) {
     124           0 :                         smbd_server_connection_terminate(req->xconn,
     125             :                                                          nt_errstr(error));
     126           0 :                         return;
     127             :                 }
     128           0 :                 return;
     129             :         }
     130             : 
     131       15148 :         SSVAL(outbody.data, 0x00, 0x3C);        /* struct size */
     132       15148 :         SSVAL(outbody.data, 0x02, out_flags);
     133       15148 :         SIVAL(outbody.data, 0x04, 0);           /* reserved */
     134       15148 :         put_long_date_full_timespec(conn->ts_res,
     135       15148 :                 (char *)outbody.data + 0x08, &out_creation_ts);
     136       15148 :         put_long_date_full_timespec(conn->ts_res,
     137       15148 :                 (char *)outbody.data + 0x10, &out_last_access_ts);
     138       15148 :         put_long_date_full_timespec(conn->ts_res,
     139       15148 :                 (char *)outbody.data + 0x18, &out_last_write_ts);
     140       15148 :         put_long_date_full_timespec(conn->ts_res,
     141       15148 :                 (char *)outbody.data + 0x20, &out_change_ts);
     142       15148 :         SBVAL(outbody.data, 0x28, out_allocation_size);
     143       15148 :         SBVAL(outbody.data, 0x30, out_end_of_file);
     144       15148 :         SIVAL(outbody.data, 0x38, out_file_attributes);
     145             : 
     146       15148 :         error = smbd_smb2_request_done(req, outbody, NULL);
     147       15148 :         if (!NT_STATUS_IS_OK(error)) {
     148        2490 :                 smbd_server_connection_terminate(req->xconn,
     149             :                                                  nt_errstr(error));
     150           0 :                 return;
     151             :         }
     152             : }
     153             : 
     154           0 : static void setup_close_full_information(connection_struct *conn,
     155             :                                 struct smb_filename *smb_fname,
     156             :                                 struct timespec *out_creation_ts,
     157             :                                 struct timespec *out_last_access_ts,
     158             :                                 struct timespec *out_last_write_ts,
     159             :                                 struct timespec *out_change_ts,
     160             :                                 uint16_t *out_flags,
     161             :                                 uint64_t *out_allocation_size,
     162             :                                 uint64_t *out_end_of_file)
     163             : {
     164           0 :         *out_flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
     165           0 :         *out_last_write_ts = smb_fname->st.st_ex_mtime;
     166           0 :         *out_last_access_ts = smb_fname->st.st_ex_atime;
     167           0 :         *out_creation_ts = get_create_timespec(conn, NULL, smb_fname);
     168           0 :         *out_change_ts = get_change_timespec(conn, NULL, smb_fname);
     169             : 
     170           0 :         if (lp_dos_filetime_resolution(SNUM(conn))) {
     171           0 :                 dos_filetime_timespec(out_creation_ts);
     172           0 :                 dos_filetime_timespec(out_last_write_ts);
     173           0 :                 dos_filetime_timespec(out_last_access_ts);
     174           0 :                 dos_filetime_timespec(out_change_ts);
     175             :         }
     176           0 :         if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
     177           0 :                 *out_end_of_file = get_file_size_stat(&smb_fname->st);
     178             :         }
     179             : 
     180           0 :         *out_allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
     181           0 : }
     182             : 
     183       15148 : static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
     184             :                                 struct files_struct **_fsp,
     185             :                                 uint16_t in_flags,
     186             :                                 uint16_t *out_flags,
     187             :                                 struct timespec *out_creation_ts,
     188             :                                 struct timespec *out_last_access_ts,
     189             :                                 struct timespec *out_last_write_ts,
     190             :                                 struct timespec *out_change_ts,
     191             :                                 uint64_t *out_allocation_size,
     192             :                                 uint64_t *out_end_of_file,
     193             :                                 uint32_t *out_file_attributes)
     194             : {
     195             :         NTSTATUS status;
     196             :         struct smb_request *smbreq;
     197       15148 :         connection_struct *conn = req->tcon->compat;
     198       15148 :         struct files_struct *fsp = *_fsp;
     199       15148 :         struct smb_filename *smb_fname = NULL;
     200             : 
     201       15148 :         *out_creation_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     202       15148 :         *out_last_access_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     203       15148 :         *out_last_write_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     204       15148 :         *out_change_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     205             : 
     206       15148 :         *out_flags = 0;
     207       15148 :         *out_allocation_size = 0;
     208       15148 :         *out_end_of_file = 0;
     209       15148 :         *out_file_attributes = 0;
     210             : 
     211       15148 :         DEBUG(10,("smbd_smb2_close: %s - %s\n",
     212             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     213             : 
     214       15148 :         smbreq = smbd_smb2_fake_smb_request(req);
     215       15148 :         if (smbreq == NULL) {
     216           0 :                 return NT_STATUS_NO_MEMORY;
     217             :         }
     218             : 
     219       15148 :         if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
     220           0 :                 *out_file_attributes = fdos_mode(fsp);
     221           0 :                 fsp->fsp_flags.fstat_before_close = true;
     222             :         }
     223             : 
     224       15148 :         status = close_file_smb(smbreq, fsp, NORMAL_CLOSE);
     225       15148 :         if (!NT_STATUS_IS_OK(status)) {
     226           0 :                 DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
     227             :                          smb_fname_str_dbg(smb_fname), nt_errstr(status)));
     228           0 :                 file_free(smbreq, fsp);
     229           0 :                 *_fsp = fsp = NULL;
     230           0 :                 return status;
     231             :         }
     232             : 
     233       15148 :         if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
     234           0 :                 setup_close_full_information(conn,
     235             :                                 fsp->fsp_name,
     236             :                                 out_creation_ts,
     237             :                                 out_last_access_ts,
     238             :                                 out_last_write_ts,
     239             :                                 out_change_ts,
     240             :                                 out_flags,
     241             :                                 out_allocation_size,
     242             :                                 out_end_of_file);
     243             :         }
     244             : 
     245       15148 :         file_free(smbreq, fsp);
     246       15148 :         *_fsp = fsp = NULL;
     247       15148 :         return NT_STATUS_OK;
     248             : }
     249             : 
     250             : struct smbd_smb2_close_state {
     251             :         struct smbd_smb2_request *smb2req;
     252             :         struct files_struct *in_fsp;
     253             :         uint16_t in_flags;
     254             :         uint16_t out_flags;
     255             :         struct timespec out_creation_ts;
     256             :         struct timespec out_last_access_ts;
     257             :         struct timespec out_last_write_ts;
     258             :         struct timespec out_change_ts;
     259             :         uint64_t out_allocation_size;
     260             :         uint64_t out_end_of_file;
     261             :         uint32_t out_file_attributes;
     262             :         struct tevent_queue *wait_queue;
     263             : };
     264             : 
     265             : static void smbd_smb2_close_wait_done(struct tevent_req *subreq);
     266             : 
     267       15148 : static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
     268             :                                                struct tevent_context *ev,
     269             :                                                struct smbd_smb2_request *smb2req,
     270             :                                                struct files_struct *in_fsp,
     271             :                                                uint16_t in_flags)
     272             : {
     273             :         struct tevent_req *req;
     274             :         struct smbd_smb2_close_state *state;
     275             :         unsigned i;
     276             :         NTSTATUS status;
     277             : 
     278       15148 :         req = tevent_req_create(mem_ctx, &state,
     279             :                                 struct smbd_smb2_close_state);
     280       15148 :         if (req == NULL) {
     281           0 :                 return NULL;
     282             :         }
     283       15148 :         state->smb2req = smb2req;
     284       15148 :         state->in_fsp = in_fsp;
     285       15148 :         state->in_flags = in_flags;
     286             : 
     287       15148 :         in_fsp->fsp_flags.closing = true;
     288             : 
     289       15148 :         i = 0;
     290       28290 :         while (i < in_fsp->num_aio_requests) {
     291           0 :                 bool ok = tevent_req_cancel(in_fsp->aio_requests[i]);
     292           0 :                 if (ok) {
     293           0 :                         continue;
     294             :                 }
     295           0 :                 i += 1;
     296             :         }
     297             : 
     298       15148 :         if (in_fsp->num_aio_requests != 0) {
     299             :                 struct tevent_req *subreq;
     300             : 
     301           0 :                 state->wait_queue = tevent_queue_create(state,
     302             :                                         "smbd_smb2_close_send_wait_queue");
     303           0 :                 if (tevent_req_nomem(state->wait_queue, req)) {
     304           0 :                         return tevent_req_post(req, ev);
     305             :                 }
     306             :                 /*
     307             :                  * Now wait until all aio requests on this fsp are
     308             :                  * finished.
     309             :                  *
     310             :                  * We don't set a callback, as we just want to block the
     311             :                  * wait queue and the talloc_free() of fsp->aio_request
     312             :                  * will remove the item from the wait queue.
     313             :                  */
     314           0 :                 subreq = tevent_queue_wait_send(in_fsp->aio_requests,
     315           0 :                                         smb2req->sconn->ev_ctx,
     316           0 :                                         state->wait_queue);
     317           0 :                 if (tevent_req_nomem(subreq, req)) {
     318           0 :                         return tevent_req_post(req, ev);
     319             :                 }
     320             : 
     321             :                 /*
     322             :                  * Now we add our own waiter to the end of the queue,
     323             :                  * this way we get notified when all pending requests are
     324             :                  * finished.
     325             :                  */
     326           0 :                 subreq = tevent_queue_wait_send(state,
     327           0 :                                         smb2req->sconn->ev_ctx,
     328           0 :                                         state->wait_queue);
     329           0 :                 if (tevent_req_nomem(subreq, req)) {
     330           0 :                         return tevent_req_post(req, ev);
     331             :                 }
     332             : 
     333           0 :                 tevent_req_set_callback(subreq, smbd_smb2_close_wait_done, req);
     334           0 :                 return req;
     335             :         }
     336             : 
     337      133426 :         status = smbd_smb2_close(smb2req,
     338       15148 :                                  &state->in_fsp,
     339       15148 :                                  state->in_flags,
     340       15148 :                                  &state->out_flags,
     341       15148 :                                  &state->out_creation_ts,
     342       15148 :                                  &state->out_last_access_ts,
     343       15148 :                                  &state->out_last_write_ts,
     344       15148 :                                  &state->out_change_ts,
     345       15148 :                                  &state->out_allocation_size,
     346       15148 :                                  &state->out_end_of_file,
     347       15148 :                                  &state->out_file_attributes);
     348       15148 :         if (tevent_req_nterror(req, status)) {
     349           0 :                 return tevent_req_post(req, ev);
     350             :         }
     351             : 
     352       15148 :         tevent_req_done(req);
     353       15148 :         return tevent_req_post(req, ev);
     354             : }
     355             : 
     356           0 : static void smbd_smb2_close_wait_done(struct tevent_req *subreq)
     357             : {
     358           0 :         struct tevent_req *req = tevent_req_callback_data(
     359             :                 subreq, struct tevent_req);
     360           0 :         struct smbd_smb2_close_state *state = tevent_req_data(
     361             :                 req, struct smbd_smb2_close_state);
     362             :         NTSTATUS status;
     363             : 
     364           0 :         tevent_queue_wait_recv(subreq);
     365           0 :         TALLOC_FREE(subreq);
     366             : 
     367           0 :         status = smbd_smb2_close(state->smb2req,
     368             :                                  &state->in_fsp,
     369           0 :                                  state->in_flags,
     370             :                                  &state->out_flags,
     371             :                                  &state->out_creation_ts,
     372             :                                  &state->out_last_access_ts,
     373             :                                  &state->out_last_write_ts,
     374             :                                  &state->out_change_ts,
     375             :                                  &state->out_allocation_size,
     376             :                                  &state->out_end_of_file,
     377             :                                  &state->out_file_attributes);
     378           0 :         if (tevent_req_nterror(req, status)) {
     379           0 :                 return;
     380             :         }
     381           0 :         tevent_req_done(req);
     382             : }
     383             : 
     384       15148 : static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
     385             :                                      uint16_t *out_flags,
     386             :                                      struct timespec *out_creation_ts,
     387             :                                      struct timespec *out_last_access_ts,
     388             :                                      struct timespec *out_last_write_ts,
     389             :                                      struct timespec *out_change_ts,
     390             :                                      uint64_t *out_allocation_size,
     391             :                                      uint64_t *out_end_of_file,
     392             :                                      uint32_t *out_file_attributes)
     393             : {
     394       13142 :         struct smbd_smb2_close_state *state =
     395       15148 :                 tevent_req_data(req,
     396             :                 struct smbd_smb2_close_state);
     397             :         NTSTATUS status;
     398             : 
     399       15148 :         if (tevent_req_is_nterror(req, &status)) {
     400           0 :                 tevent_req_received(req);
     401           0 :                 return status;
     402             :         }
     403             : 
     404       15148 :         *out_flags = state->out_flags;
     405       15148 :         *out_creation_ts = state->out_creation_ts;
     406       15148 :         *out_last_access_ts = state->out_last_access_ts;
     407       15148 :         *out_last_write_ts = state->out_last_write_ts;
     408       15148 :         *out_change_ts = state->out_change_ts;
     409       15148 :         *out_allocation_size = state->out_allocation_size;
     410       15148 :         *out_end_of_file = state->out_end_of_file;
     411       15148 :         *out_file_attributes = state->out_file_attributes;
     412             : 
     413       15148 :         tevent_req_received(req);
     414       15148 :         return NT_STATUS_OK;
     415             : }

Generated by: LCOV version 1.13