LCOV - code coverage report
Current view: top level - source3/smbd - smb2_close.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 160 197 81.2 %
Date: 2021-08-25 13:27:56 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      363199 : 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      363199 :         status = smbd_smb2_request_verify_sizes(req, 0x18);
      58      363199 :         if (!NT_STATUS_IS_OK(status)) {
      59           0 :                 return smbd_smb2_request_error(req, status);
      60             :         }
      61      363199 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      62             : 
      63      363199 :         in_flags                = SVAL(inbody, 0x02);
      64      363199 :         in_file_id_persistent   = BVAL(inbody, 0x08);
      65      363199 :         in_file_id_volatile     = BVAL(inbody, 0x10);
      66             : 
      67      363199 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
      68      363199 :         if (in_fsp == NULL) {
      69           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
      70             :         }
      71             : 
      72      363199 :         subreq = smbd_smb2_close_send(req, req->sconn->ev_ctx,
      73             :                                       req, in_fsp, in_flags);
      74      363199 :         if (subreq == NULL) {
      75           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
      76             :         }
      77      363199 :         tevent_req_set_callback(subreq, smbd_smb2_request_close_done, req);
      78             : 
      79      363199 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
      80             : }
      81             : 
      82      363199 : static void smbd_smb2_request_close_done(struct tevent_req *subreq)
      83             : {
      84      363199 :         struct smbd_smb2_request *req =
      85      363199 :                 tevent_req_callback_data(subreq,
      86             :                 struct smbd_smb2_request);
      87             :         DATA_BLOB outbody;
      88      363199 :         uint16_t out_flags = 0;
      89      363199 :         connection_struct *conn = req->tcon->compat;
      90      363199 :         struct timespec out_creation_ts = { 0, };
      91      363199 :         struct timespec out_last_access_ts = { 0, };
      92      363199 :         struct timespec out_last_write_ts = { 0, };
      93      363199 :         struct timespec out_change_ts = { 0, };
      94      363199 :         uint64_t out_allocation_size = 0;
      95      363199 :         uint64_t out_end_of_file = 0;
      96      363199 :         uint32_t out_file_attributes = 0;
      97             :         NTSTATUS status;
      98             :         NTSTATUS error;
      99             : 
     100      363199 :         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      363199 :         TALLOC_FREE(subreq);
     110      363199 :         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      363199 :         outbody = smbd_smb2_generate_outbody(req, 0x3C);
     121      363199 :         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      363199 :         SSVAL(outbody.data, 0x00, 0x3C);        /* struct size */
     132      363199 :         SSVAL(outbody.data, 0x02, out_flags);
     133      363199 :         SIVAL(outbody.data, 0x04, 0);           /* reserved */
     134      363199 :         put_long_date_full_timespec(conn->ts_res,
     135      362750 :                 (char *)outbody.data + 0x08, &out_creation_ts);
     136      363199 :         put_long_date_full_timespec(conn->ts_res,
     137      362750 :                 (char *)outbody.data + 0x10, &out_last_access_ts);
     138      363199 :         put_long_date_full_timespec(conn->ts_res,
     139      362750 :                 (char *)outbody.data + 0x18, &out_last_write_ts);
     140      363199 :         put_long_date_full_timespec(conn->ts_res,
     141      362750 :                 (char *)outbody.data + 0x20, &out_change_ts);
     142      363199 :         SBVAL(outbody.data, 0x28, out_allocation_size);
     143      363199 :         SBVAL(outbody.data, 0x30, out_end_of_file);
     144      363199 :         SIVAL(outbody.data, 0x38, out_file_attributes);
     145             : 
     146      363199 :         error = smbd_smb2_request_done(req, outbody, NULL);
     147      363199 :         if (!NT_STATUS_IS_OK(error)) {
     148        4780 :                 smbd_server_connection_terminate(req->xconn,
     149             :                                                  nt_errstr(error));
     150           0 :                 return;
     151             :         }
     152             : }
     153             : 
     154          24 : static void setup_close_full_information(connection_struct *conn,
     155             :                                 struct smb_filename *smb_fname,
     156             :                                 bool posix_open,
     157             :                                 struct timespec *out_creation_ts,
     158             :                                 struct timespec *out_last_access_ts,
     159             :                                 struct timespec *out_last_write_ts,
     160             :                                 struct timespec *out_change_ts,
     161             :                                 uint16_t *out_flags,
     162             :                                 uint64_t *out_allocation_size,
     163             :                                 uint64_t *out_end_of_file,
     164             :                                 uint32_t *out_file_attributes)
     165             : {
     166             :         NTSTATUS status;
     167             :         int ret;
     168             : 
     169          24 :         status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
     170          24 :         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
     171           0 :             (smb_fname->flags & SMB_FILENAME_POSIX_PATH) &&
     172           0 :             S_ISLNK(smb_fname->st.st_ex_mode))
     173             :         {
     174           0 :                 status = NT_STATUS_OK;
     175             :         }
     176          24 :         if (!NT_STATUS_IS_OK(status)) {
     177           0 :                 return;
     178             :         }
     179             : 
     180          24 :         if (posix_open) {
     181           0 :                 ret = SMB_VFS_LSTAT(conn, smb_fname);
     182             :         } else {
     183          24 :                 ret = SMB_VFS_STAT(conn, smb_fname);
     184             :         }
     185          24 :         if (ret != 0) {
     186           0 :                 return;
     187             :         }
     188             : 
     189          24 :         *out_flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
     190          24 :         *out_file_attributes = fdos_mode(smb_fname->fsp);
     191          24 :         *out_last_write_ts = smb_fname->st.st_ex_mtime;
     192          24 :         *out_last_access_ts = smb_fname->st.st_ex_atime;
     193          24 :         *out_creation_ts = get_create_timespec(conn, NULL, smb_fname);
     194          24 :         *out_change_ts = get_change_timespec(conn, NULL, smb_fname);
     195             : 
     196          24 :         if (lp_dos_filetime_resolution(SNUM(conn))) {
     197           0 :                 dos_filetime_timespec(out_creation_ts);
     198           0 :                 dos_filetime_timespec(out_last_write_ts);
     199           0 :                 dos_filetime_timespec(out_last_access_ts);
     200           0 :                 dos_filetime_timespec(out_change_ts);
     201             :         }
     202          24 :         if (!(*out_file_attributes & FILE_ATTRIBUTE_DIRECTORY)) {
     203          24 :                 *out_end_of_file = get_file_size_stat(&smb_fname->st);
     204             :         }
     205             : 
     206          24 :         *out_allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
     207             : }
     208             : 
     209      363199 : static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
     210             :                                 struct files_struct *fsp,
     211             :                                 uint16_t in_flags,
     212             :                                 uint16_t *out_flags,
     213             :                                 struct timespec *out_creation_ts,
     214             :                                 struct timespec *out_last_access_ts,
     215             :                                 struct timespec *out_last_write_ts,
     216             :                                 struct timespec *out_change_ts,
     217             :                                 uint64_t *out_allocation_size,
     218             :                                 uint64_t *out_end_of_file,
     219             :                                 uint32_t *out_file_attributes)
     220             : {
     221             :         NTSTATUS status;
     222             :         struct smb_request *smbreq;
     223      363199 :         connection_struct *conn = req->tcon->compat;
     224      363199 :         struct smb_filename *smb_fname = NULL;
     225      363199 :         uint64_t allocation_size = 0;
     226      363199 :         uint64_t file_size = 0;
     227      363199 :         uint32_t dos_attrs = 0;
     228      363199 :         uint16_t flags = 0;
     229      363199 :         bool posix_open = false;
     230             : 
     231      363199 :         *out_creation_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     232      363199 :         *out_last_access_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     233      363199 :         *out_last_write_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     234      363199 :         *out_change_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
     235             : 
     236      363199 :         *out_flags = 0;
     237      363199 :         *out_allocation_size = 0;
     238      363199 :         *out_end_of_file = 0;
     239      363199 :         *out_file_attributes = 0;
     240             : 
     241      363199 :         DEBUG(10,("smbd_smb2_close: %s - %s\n",
     242             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     243             : 
     244      363199 :         smbreq = smbd_smb2_fake_smb_request(req);
     245      363199 :         if (smbreq == NULL) {
     246           0 :                 return NT_STATUS_NO_MEMORY;
     247             :         }
     248             : 
     249      363199 :         posix_open = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN);
     250      363199 :         smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
     251      363199 :         if (smb_fname == NULL) {
     252           0 :                 return NT_STATUS_NO_MEMORY;
     253             :         }
     254             : 
     255      363223 :         if ((in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) &&
     256          48 :             (fsp->fsp_flags.initial_delete_on_close ||
     257             :              fsp->fsp_flags.delete_on_close))
     258             :         {
     259             :                 /*
     260             :                  * We might be deleting the file. Ensure we
     261             :                  * return valid data from before the file got
     262             :                  * removed.
     263             :                  */
     264           0 :                 setup_close_full_information(conn,
     265             :                                 smb_fname,
     266             :                                 posix_open,
     267             :                                 out_creation_ts,
     268             :                                 out_last_access_ts,
     269             :                                 out_last_write_ts,
     270             :                                 out_change_ts,
     271             :                                 &flags,
     272             :                                 &allocation_size,
     273             :                                 &file_size,
     274             :                                 &dos_attrs);
     275             :         }
     276             : 
     277      363199 :         status = close_file(smbreq, fsp, NORMAL_CLOSE);
     278      363199 :         if (!NT_STATUS_IS_OK(status)) {
     279           0 :                 DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
     280             :                          smb_fname_str_dbg(smb_fname), nt_errstr(status)));
     281           0 :                 return status;
     282             :         }
     283             : 
     284      363199 :         if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
     285          24 :                 setup_close_full_information(conn,
     286             :                                 smb_fname,
     287             :                                 posix_open,
     288             :                                 out_creation_ts,
     289             :                                 out_last_access_ts,
     290             :                                 out_last_write_ts,
     291             :                                 out_change_ts,
     292             :                                 &flags,
     293             :                                 &allocation_size,
     294             :                                 &file_size,
     295             :                                 &dos_attrs);
     296             :         }
     297             : 
     298      363199 :         *out_flags = flags;
     299      363199 :         *out_allocation_size = allocation_size;
     300      363199 :         *out_end_of_file = file_size;
     301      363199 :         *out_file_attributes = dos_attrs;
     302             : 
     303      363199 :         return NT_STATUS_OK;
     304             : }
     305             : 
     306             : struct smbd_smb2_close_state {
     307             :         struct smbd_smb2_request *smb2req;
     308             :         struct files_struct *in_fsp;
     309             :         uint16_t in_flags;
     310             :         uint16_t out_flags;
     311             :         struct timespec out_creation_ts;
     312             :         struct timespec out_last_access_ts;
     313             :         struct timespec out_last_write_ts;
     314             :         struct timespec out_change_ts;
     315             :         uint64_t out_allocation_size;
     316             :         uint64_t out_end_of_file;
     317             :         uint32_t out_file_attributes;
     318             :         struct tevent_queue *wait_queue;
     319             : };
     320             : 
     321             : static void smbd_smb2_close_wait_done(struct tevent_req *subreq);
     322             : 
     323      363199 : static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
     324             :                                                struct tevent_context *ev,
     325             :                                                struct smbd_smb2_request *smb2req,
     326             :                                                struct files_struct *in_fsp,
     327             :                                                uint16_t in_flags)
     328             : {
     329             :         struct tevent_req *req;
     330             :         struct smbd_smb2_close_state *state;
     331             :         unsigned i;
     332             :         NTSTATUS status;
     333             : 
     334      363199 :         req = tevent_req_create(mem_ctx, &state,
     335             :                                 struct smbd_smb2_close_state);
     336      363199 :         if (req == NULL) {
     337           0 :                 return NULL;
     338             :         }
     339      363199 :         state->smb2req = smb2req;
     340      363199 :         state->in_fsp = in_fsp;
     341      363199 :         state->in_flags = in_flags;
     342             : 
     343      363199 :         in_fsp->fsp_flags.closing = true;
     344             : 
     345      363199 :         i = 0;
     346      726414 :         while (i < in_fsp->num_aio_requests) {
     347          16 :                 bool ok = tevent_req_cancel(in_fsp->aio_requests[i]);
     348          16 :                 if (ok) {
     349           8 :                         continue;
     350             :                 }
     351           8 :                 i += 1;
     352             :         }
     353             : 
     354      363199 :         if (in_fsp->num_aio_requests != 0) {
     355             :                 struct tevent_req *subreq;
     356             : 
     357           8 :                 state->wait_queue = tevent_queue_create(state,
     358             :                                         "smbd_smb2_close_send_wait_queue");
     359           8 :                 if (tevent_req_nomem(state->wait_queue, req)) {
     360           0 :                         return tevent_req_post(req, ev);
     361             :                 }
     362             :                 /*
     363             :                  * Now wait until all aio requests on this fsp are
     364             :                  * finished.
     365             :                  *
     366             :                  * We don't set a callback, as we just want to block the
     367             :                  * wait queue and the talloc_free() of fsp->aio_request
     368             :                  * will remove the item from the wait queue.
     369             :                  */
     370          16 :                 subreq = tevent_queue_wait_send(in_fsp->aio_requests,
     371           8 :                                         smb2req->sconn->ev_ctx,
     372           8 :                                         state->wait_queue);
     373           8 :                 if (tevent_req_nomem(subreq, req)) {
     374           0 :                         return tevent_req_post(req, ev);
     375             :                 }
     376             : 
     377             :                 /*
     378             :                  * Now we add our own waiter to the end of the queue,
     379             :                  * this way we get notified when all pending requests are
     380             :                  * finished.
     381             :                  */
     382          16 :                 subreq = tevent_queue_wait_send(state,
     383           8 :                                         smb2req->sconn->ev_ctx,
     384           8 :                                         state->wait_queue);
     385           8 :                 if (tevent_req_nomem(subreq, req)) {
     386           0 :                         return tevent_req_post(req, ev);
     387             :                 }
     388             : 
     389           8 :                 tevent_req_set_callback(subreq, smbd_smb2_close_wait_done, req);
     390           8 :                 return req;
     391             :         }
     392             : 
     393     3628318 :         status = smbd_smb2_close(smb2req,
     394      362742 :                                  state->in_fsp,
     395      363191 :                                  state->in_flags,
     396      362742 :                                  &state->out_flags,
     397      362742 :                                  &state->out_creation_ts,
     398      362742 :                                  &state->out_last_access_ts,
     399      362742 :                                  &state->out_last_write_ts,
     400      362742 :                                  &state->out_change_ts,
     401      362742 :                                  &state->out_allocation_size,
     402      362742 :                                  &state->out_end_of_file,
     403      363191 :                                  &state->out_file_attributes);
     404      363191 :         if (tevent_req_nterror(req, status)) {
     405           0 :                 return tevent_req_post(req, ev);
     406             :         }
     407             : 
     408      363191 :         tevent_req_done(req);
     409      363191 :         return tevent_req_post(req, ev);
     410             : }
     411             : 
     412           8 : static void smbd_smb2_close_wait_done(struct tevent_req *subreq)
     413             : {
     414           8 :         struct tevent_req *req = tevent_req_callback_data(
     415             :                 subreq, struct tevent_req);
     416           8 :         struct smbd_smb2_close_state *state = tevent_req_data(
     417             :                 req, struct smbd_smb2_close_state);
     418             :         NTSTATUS status;
     419             : 
     420           8 :         tevent_queue_wait_recv(subreq);
     421           8 :         TALLOC_FREE(subreq);
     422             : 
     423          16 :         status = smbd_smb2_close(state->smb2req,
     424             :                                  state->in_fsp,
     425           8 :                                  state->in_flags,
     426             :                                  &state->out_flags,
     427             :                                  &state->out_creation_ts,
     428             :                                  &state->out_last_access_ts,
     429             :                                  &state->out_last_write_ts,
     430             :                                  &state->out_change_ts,
     431             :                                  &state->out_allocation_size,
     432             :                                  &state->out_end_of_file,
     433             :                                  &state->out_file_attributes);
     434           8 :         if (tevent_req_nterror(req, status)) {
     435           0 :                 return;
     436             :         }
     437           8 :         tevent_req_done(req);
     438             : }
     439             : 
     440      363199 : static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
     441             :                                      uint16_t *out_flags,
     442             :                                      struct timespec *out_creation_ts,
     443             :                                      struct timespec *out_last_access_ts,
     444             :                                      struct timespec *out_last_write_ts,
     445             :                                      struct timespec *out_change_ts,
     446             :                                      uint64_t *out_allocation_size,
     447             :                                      uint64_t *out_end_of_file,
     448             :                                      uint32_t *out_file_attributes)
     449             : {
     450      363199 :         struct smbd_smb2_close_state *state =
     451      363199 :                 tevent_req_data(req,
     452             :                 struct smbd_smb2_close_state);
     453             :         NTSTATUS status;
     454             : 
     455      363199 :         if (tevent_req_is_nterror(req, &status)) {
     456           0 :                 tevent_req_received(req);
     457           0 :                 return status;
     458             :         }
     459             : 
     460      363199 :         *out_flags = state->out_flags;
     461      363199 :         *out_creation_ts = state->out_creation_ts;
     462      363199 :         *out_last_access_ts = state->out_last_access_ts;
     463      363199 :         *out_last_write_ts = state->out_last_write_ts;
     464      363199 :         *out_change_ts = state->out_change_ts;
     465      363199 :         *out_allocation_size = state->out_allocation_size;
     466      363199 :         *out_end_of_file = state->out_end_of_file;
     467      363199 :         *out_file_attributes = state->out_file_attributes;
     468             : 
     469      363199 :         tevent_req_received(req);
     470      363199 :         return NT_STATUS_OK;
     471             : }

Generated by: LCOV version 1.13