LCOV - code coverage report
Current view: top level - source3/smbd - smb2_close.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 180 203 88.7 %
Date: 2024-04-21 15:09:00 Functions: 7 7 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             : 
      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      369080 : NTSTATUS smbd_smb2_request_process_close(struct smbd_smb2_request *req)
      48             : {
      49         505 :         const uint8_t *inbody;
      50         505 :         uint16_t in_flags;
      51         505 :         uint64_t in_file_id_persistent;
      52         505 :         uint64_t in_file_id_volatile;
      53         505 :         struct files_struct *in_fsp;
      54         505 :         NTSTATUS status;
      55         505 :         struct tevent_req *subreq;
      56             : 
      57      369080 :         status = smbd_smb2_request_verify_sizes(req, 0x18);
      58      369080 :         if (!NT_STATUS_IS_OK(status)) {
      59           0 :                 return smbd_smb2_request_error(req, status);
      60             :         }
      61      369080 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      62             : 
      63      369080 :         in_flags                = SVAL(inbody, 0x02);
      64      369080 :         in_file_id_persistent   = BVAL(inbody, 0x08);
      65      369080 :         in_file_id_volatile     = BVAL(inbody, 0x10);
      66             : 
      67      369080 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
      68      369080 :         if (in_fsp == NULL) {
      69           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
      70             :         }
      71             : 
      72      369080 :         subreq = smbd_smb2_close_send(req, req->sconn->ev_ctx,
      73             :                                       req, in_fsp, in_flags);
      74      369080 :         if (subreq == NULL) {
      75           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
      76             :         }
      77      369080 :         tevent_req_set_callback(subreq, smbd_smb2_request_close_done, req);
      78             : 
      79      369080 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
      80             : }
      81             : 
      82      369080 : static void smbd_smb2_request_close_done(struct tevent_req *subreq)
      83             : {
      84         505 :         struct smbd_smb2_request *req =
      85      369080 :                 tevent_req_callback_data(subreq,
      86             :                 struct smbd_smb2_request);
      87         505 :         DATA_BLOB outbody;
      88      369080 :         uint16_t out_flags = 0;
      89      369080 :         connection_struct *conn = req->tcon->compat;
      90      369080 :         struct timespec out_creation_ts = { 0, };
      91      369080 :         struct timespec out_last_access_ts = { 0, };
      92      369080 :         struct timespec out_last_write_ts = { 0, };
      93      369080 :         struct timespec out_change_ts = { 0, };
      94      369080 :         uint64_t out_allocation_size = 0;
      95      369080 :         uint64_t out_end_of_file = 0;
      96      369080 :         uint32_t out_file_attributes = 0;
      97         505 :         NTSTATUS status;
      98         505 :         NTSTATUS error;
      99             : 
     100      369080 :         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      369080 :         TALLOC_FREE(subreq);
     110      369080 :         if (!NT_STATUS_IS_OK(status)) {
     111           4 :                 error = smbd_smb2_request_error(req, status);
     112           4 :                 if (!NT_STATUS_IS_OK(error)) {
     113           0 :                         smbd_server_connection_terminate(req->xconn,
     114             :                                                          nt_errstr(error));
     115           4 :                         return;
     116             :                 }
     117           4 :                 return;
     118             :         }
     119             : 
     120      369076 :         outbody = smbd_smb2_generate_outbody(req, 0x3C);
     121      369076 :         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      369076 :         SSVAL(outbody.data, 0x00, 0x3C);        /* struct size */
     132      369076 :         SSVAL(outbody.data, 0x02, out_flags);
     133      369076 :         SIVAL(outbody.data, 0x04, 0);           /* reserved */
     134      369076 :         put_long_date_full_timespec(conn->ts_res,
     135      368571 :                 (char *)outbody.data + 0x08, &out_creation_ts);
     136      369076 :         put_long_date_full_timespec(conn->ts_res,
     137      368571 :                 (char *)outbody.data + 0x10, &out_last_access_ts);
     138      369076 :         put_long_date_full_timespec(conn->ts_res,
     139      368571 :                 (char *)outbody.data + 0x18, &out_last_write_ts);
     140      369076 :         put_long_date_full_timespec(conn->ts_res,
     141      368571 :                 (char *)outbody.data + 0x20, &out_change_ts);
     142      369076 :         SBVAL(outbody.data, 0x28, out_allocation_size);
     143      369076 :         SBVAL(outbody.data, 0x30, out_end_of_file);
     144      369076 :         SIVAL(outbody.data, 0x38, out_file_attributes);
     145             : 
     146      369076 :         error = smbd_smb2_request_done(req, outbody, NULL);
     147      369076 :         if (!NT_STATUS_IS_OK(error)) {
     148        3943 :                 smbd_server_connection_terminate(req->xconn,
     149             :                                                  nt_errstr(error));
     150         147 :                 return;
     151             :         }
     152             : }
     153             : 
     154          34 : 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          34 :         *out_flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
     165          34 :         *out_last_write_ts = smb_fname->st.st_ex_mtime;
     166          34 :         *out_last_access_ts = smb_fname->st.st_ex_atime;
     167          34 :         *out_creation_ts = get_create_timespec(conn, NULL, smb_fname);
     168          34 :         *out_change_ts = get_change_timespec(conn, NULL, smb_fname);
     169             : 
     170          34 :         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          34 :         if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
     177          34 :                 *out_end_of_file = get_file_size_stat(&smb_fname->st);
     178             :         }
     179             : 
     180          34 :         *out_allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
     181          34 : }
     182             : 
     183      369080 : 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         505 :         NTSTATUS status;
     196         505 :         struct smb_request *smbreq;
     197      369080 :         connection_struct *conn = req->tcon->compat;
     198      369080 :         struct files_struct *fsp = *_fsp;
     199      369080 :         struct smb_filename *smb_fname = NULL;
     200             : 
     201      369080 :         *out_creation_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     202      369080 :         *out_last_access_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     203      369080 :         *out_last_write_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     204      369080 :         *out_change_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     205             : 
     206      369080 :         *out_flags = 0;
     207      369080 :         *out_allocation_size = 0;
     208      369080 :         *out_end_of_file = 0;
     209      369080 :         *out_file_attributes = 0;
     210             : 
     211      369080 :         DEBUG(10,("smbd_smb2_close: %s - %s\n",
     212             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     213             : 
     214      369080 :         smbreq = smbd_smb2_fake_smb_request(req, fsp);
     215      369080 :         if (smbreq == NULL) {
     216           0 :                 return NT_STATUS_NO_MEMORY;
     217             :         }
     218             : 
     219      369080 :         if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
     220          34 :                 *out_file_attributes = fdos_mode(fsp);
     221          34 :                 fsp->fsp_flags.fstat_before_close = true;
     222             :         }
     223             : 
     224      369080 :         status = close_file_smb(smbreq, fsp, NORMAL_CLOSE);
     225      369080 :         if (!NT_STATUS_IS_OK(status)) {
     226           4 :                 DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
     227             :                          smb_fname_str_dbg(smb_fname), nt_errstr(status)));
     228           4 :                 file_free(smbreq, fsp);
     229           4 :                 *_fsp = fsp = NULL;
     230           4 :                 return status;
     231             :         }
     232             : 
     233      369076 :         if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
     234          34 :                 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      369076 :         file_free(smbreq, fsp);
     246      369076 :         *_fsp = fsp = NULL;
     247      369076 :         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      369080 : 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         505 :         struct tevent_req *req;
     274         505 :         struct smbd_smb2_close_state *state;
     275      369080 :         const char *fsp_name_str = NULL;
     276      369080 :         const char *fsp_fnum_str = NULL;
     277         505 :         unsigned i;
     278         505 :         NTSTATUS status;
     279             : 
     280      369080 :         if (CHECK_DEBUGLVL(DBGLVL_INFO)) {
     281           0 :                 fsp_name_str = fsp_str_dbg(in_fsp);
     282           0 :                 fsp_fnum_str = fsp_fnum_dbg(in_fsp);
     283             :         }
     284             : 
     285      369080 :         DBG_DEBUG("%s - %s\n", fsp_name_str, fsp_fnum_str);
     286             : 
     287      369080 :         req = tevent_req_create(mem_ctx, &state,
     288             :                                 struct smbd_smb2_close_state);
     289      369080 :         if (req == NULL) {
     290           0 :                 return NULL;
     291             :         }
     292      369080 :         state->smb2req = smb2req;
     293      369080 :         state->in_fsp = in_fsp;
     294      369080 :         state->in_flags = in_flags;
     295             : 
     296      369080 :         in_fsp->fsp_flags.closing = true;
     297             : 
     298      369080 :         i = 0;
     299      369098 :         while (i < in_fsp->num_aio_requests) {
     300          18 :                 bool ok = tevent_req_cancel(in_fsp->aio_requests[i]);
     301          18 :                 if (ok) {
     302           8 :                         continue;
     303             :                 }
     304          10 :                 i += 1;
     305             :         }
     306             : 
     307      369080 :         if (in_fsp->num_aio_requests != 0) {
     308           0 :                 struct tevent_req *subreq;
     309             : 
     310          10 :                 state->wait_queue = tevent_queue_create(state,
     311             :                                         "smbd_smb2_close_send_wait_queue");
     312          10 :                 if (tevent_req_nomem(state->wait_queue, req)) {
     313           0 :                         return tevent_req_post(req, ev);
     314             :                 }
     315             :                 /*
     316             :                  * Now wait until all aio requests on this fsp are
     317             :                  * finished.
     318             :                  *
     319             :                  * We don't set a callback, as we just want to block the
     320             :                  * wait queue and the talloc_free() of fsp->aio_request
     321             :                  * will remove the item from the wait queue.
     322             :                  */
     323          10 :                 subreq = tevent_queue_wait_send(in_fsp->aio_requests,
     324          10 :                                         smb2req->sconn->ev_ctx,
     325          10 :                                         state->wait_queue);
     326          10 :                 if (tevent_req_nomem(subreq, req)) {
     327           0 :                         return tevent_req_post(req, ev);
     328             :                 }
     329             : 
     330             :                 /*
     331             :                  * Now we add our own waiter to the end of the queue,
     332             :                  * this way we get notified when all pending requests are
     333             :                  * finished.
     334             :                  */
     335          10 :                 subreq = tevent_queue_wait_send(state,
     336          10 :                                         smb2req->sconn->ev_ctx,
     337          10 :                                         state->wait_queue);
     338          10 :                 if (tevent_req_nomem(subreq, req)) {
     339           0 :                         return tevent_req_post(req, ev);
     340             :                 }
     341             : 
     342          10 :                 tevent_req_set_callback(subreq, smbd_smb2_close_wait_done, req);
     343          10 :                 return req;
     344             :         }
     345             : 
     346      369070 :         status = smbd_smb2_close(smb2req,
     347      368565 :                                  &state->in_fsp,
     348      369070 :                                  state->in_flags,
     349      368565 :                                  &state->out_flags,
     350      368565 :                                  &state->out_creation_ts,
     351      368565 :                                  &state->out_last_access_ts,
     352      368565 :                                  &state->out_last_write_ts,
     353      368565 :                                  &state->out_change_ts,
     354      368565 :                                  &state->out_allocation_size,
     355      368565 :                                  &state->out_end_of_file,
     356      369070 :                                  &state->out_file_attributes);
     357      369070 :         if (tevent_req_nterror(req, status)) {
     358           4 :                 DBG_INFO("%s - %s: close file failed: %s\n",
     359             :                          fsp_name_str, fsp_fnum_str,
     360             :                          nt_errstr(status));
     361           4 :                 return tevent_req_post(req, ev);
     362             :         }
     363             : 
     364      369066 :         tevent_req_done(req);
     365      369066 :         return tevent_req_post(req, ev);
     366             : }
     367             : 
     368          10 : static void smbd_smb2_close_wait_done(struct tevent_req *subreq)
     369             : {
     370          10 :         struct tevent_req *req = tevent_req_callback_data(
     371             :                 subreq, struct tevent_req);
     372          10 :         struct smbd_smb2_close_state *state = tevent_req_data(
     373             :                 req, struct smbd_smb2_close_state);
     374           0 :         NTSTATUS status;
     375             : 
     376          10 :         tevent_queue_wait_recv(subreq);
     377          10 :         TALLOC_FREE(subreq);
     378             : 
     379          10 :         status = smbd_smb2_close(state->smb2req,
     380             :                                  &state->in_fsp,
     381          10 :                                  state->in_flags,
     382             :                                  &state->out_flags,
     383             :                                  &state->out_creation_ts,
     384             :                                  &state->out_last_access_ts,
     385             :                                  &state->out_last_write_ts,
     386             :                                  &state->out_change_ts,
     387             :                                  &state->out_allocation_size,
     388             :                                  &state->out_end_of_file,
     389             :                                  &state->out_file_attributes);
     390          10 :         if (tevent_req_nterror(req, status)) {
     391           0 :                 return;
     392             :         }
     393          10 :         tevent_req_done(req);
     394             : }
     395             : 
     396      369080 : static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
     397             :                                      uint16_t *out_flags,
     398             :                                      struct timespec *out_creation_ts,
     399             :                                      struct timespec *out_last_access_ts,
     400             :                                      struct timespec *out_last_write_ts,
     401             :                                      struct timespec *out_change_ts,
     402             :                                      uint64_t *out_allocation_size,
     403             :                                      uint64_t *out_end_of_file,
     404             :                                      uint32_t *out_file_attributes)
     405             : {
     406         505 :         struct smbd_smb2_close_state *state =
     407      369080 :                 tevent_req_data(req,
     408             :                 struct smbd_smb2_close_state);
     409         505 :         NTSTATUS status;
     410             : 
     411      369080 :         if (tevent_req_is_nterror(req, &status)) {
     412           4 :                 tevent_req_received(req);
     413           4 :                 return status;
     414             :         }
     415             : 
     416      369076 :         *out_flags = state->out_flags;
     417      369076 :         *out_creation_ts = state->out_creation_ts;
     418      369076 :         *out_last_access_ts = state->out_last_access_ts;
     419      369076 :         *out_last_write_ts = state->out_last_write_ts;
     420      369076 :         *out_change_ts = state->out_change_ts;
     421      369076 :         *out_allocation_size = state->out_allocation_size;
     422      369076 :         *out_end_of_file = state->out_end_of_file;
     423      369076 :         *out_file_attributes = state->out_file_attributes;
     424             : 
     425      369076 :         tevent_req_received(req);
     426      369076 :         return NT_STATUS_OK;
     427             : }

Generated by: LCOV version 1.14