LCOV - code coverage report
Current view: top level - source3/smbd - close.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 285 690 41.3 %
Date: 2024-06-13 04:01:37 Functions: 14 16 87.5 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    file closing
       4             :    Copyright (C) Andrew Tridgell 1992-1998
       5             :    Copyright (C) Jeremy Allison 1992-2007.
       6             :    Copyright (C) Volker Lendecke 2005
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "system/filesys.h"
      24             : #include "lib/util/server_id.h"
      25             : #include "printing.h"
      26             : #include "locking/share_mode_lock.h"
      27             : #include "smbd/smbd.h"
      28             : #include "smbd/globals.h"
      29             : #include "smbd/smbXsrv_open.h"
      30             : #include "smbd/scavenger.h"
      31             : #include "fake_file.h"
      32             : #include "transfer_file.h"
      33             : #include "auth.h"
      34             : #include "messages.h"
      35             : #include "../librpc/gen_ndr/open_files.h"
      36             : #include "lib/util/tevent_ntstatus.h"
      37             : 
      38             : /****************************************************************************
      39             :  Run a file if it is a magic script.
      40             : ****************************************************************************/
      41             : 
      42        1838 : static NTSTATUS check_magic(struct files_struct *fsp)
      43             : {
      44             :         int ret;
      45        1552 :         const struct loadparm_substitution *lp_sub =
      46         286 :                 loadparm_s3_global_substitution();
      47        1838 :         const char *magic_output = NULL;
      48             :         SMB_STRUCT_STAT st;
      49             :         int tmp_fd, outfd;
      50        1838 :         TALLOC_CTX *ctx = NULL;
      51             :         const char *p;
      52        1838 :         struct connection_struct *conn = fsp->conn;
      53        1838 :         char *fname = NULL;
      54             :         NTSTATUS status;
      55             : 
      56        1838 :         if (!*lp_magic_script(talloc_tos(), lp_sub, SNUM(conn))) {
      57        1838 :                 return NT_STATUS_OK;
      58             :         }
      59             : 
      60           0 :         DEBUG(5,("checking magic for %s\n", fsp_str_dbg(fsp)));
      61             : 
      62           0 :         ctx = talloc_stackframe();
      63             : 
      64           0 :         fname = fsp->fsp_name->base_name;
      65             : 
      66           0 :         if (!(p = strrchr_m(fname,'/'))) {
      67           0 :                 p = fname;
      68             :         } else {
      69           0 :                 p++;
      70             :         }
      71             : 
      72           0 :         if (!strequal(lp_magic_script(talloc_tos(), lp_sub, SNUM(conn)),p)) {
      73           0 :                 status = NT_STATUS_OK;
      74           0 :                 goto out;
      75             :         }
      76             : 
      77           0 :         if (*lp_magic_output(talloc_tos(), lp_sub, SNUM(conn))) {
      78           0 :                 magic_output = lp_magic_output(talloc_tos(), lp_sub, SNUM(conn));
      79             :         } else {
      80           0 :                 magic_output = talloc_asprintf(ctx,
      81             :                                 "%s.out",
      82             :                                 fname);
      83             :         }
      84           0 :         if (!magic_output) {
      85           0 :                 status = NT_STATUS_NO_MEMORY;
      86           0 :                 goto out;
      87             :         }
      88             : 
      89             :         /* Ensure we don't depend on user's PATH. */
      90           0 :         p = talloc_asprintf(ctx, "./%s", fname);
      91           0 :         if (!p) {
      92           0 :                 status = NT_STATUS_NO_MEMORY;
      93           0 :                 goto out;
      94             :         }
      95             : 
      96           0 :         if (chmod(fname, 0755) == -1) {
      97           0 :                 status = map_nt_error_from_unix(errno);
      98           0 :                 goto out;
      99             :         }
     100           0 :         ret = smbrun(p, &tmp_fd, NULL);
     101           0 :         DEBUG(3,("Invoking magic command %s gave %d\n",
     102             :                 p,ret));
     103             : 
     104           0 :         unlink(fname);
     105           0 :         if (ret != 0 || tmp_fd == -1) {
     106           0 :                 if (tmp_fd != -1) {
     107           0 :                         close(tmp_fd);
     108             :                 }
     109           0 :                 status = NT_STATUS_UNSUCCESSFUL;
     110           0 :                 goto out;
     111             :         }
     112           0 :         outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600);
     113           0 :         if (outfd == -1) {
     114           0 :                 int err = errno;
     115           0 :                 close(tmp_fd);
     116           0 :                 status = map_nt_error_from_unix(err);
     117           0 :                 goto out;
     118             :         }
     119             : 
     120           0 :         if (sys_fstat(tmp_fd, &st, false) == -1) {
     121           0 :                 int err = errno;
     122           0 :                 close(tmp_fd);
     123           0 :                 close(outfd);
     124           0 :                 status = map_nt_error_from_unix(err);
     125           0 :                 goto out;
     126             :         }
     127             : 
     128           0 :         if (transfer_file(tmp_fd,outfd,(off_t)st.st_ex_size) == (off_t)-1) {
     129           0 :                 int err = errno;
     130           0 :                 close(tmp_fd);
     131           0 :                 close(outfd);
     132           0 :                 status = map_nt_error_from_unix(err);
     133           0 :                 goto out;
     134             :         }
     135           0 :         close(tmp_fd);
     136           0 :         if (close(outfd) == -1) {
     137           0 :                 status = map_nt_error_from_unix(errno);
     138           0 :                 goto out;
     139             :         }
     140             : 
     141           0 :         status = NT_STATUS_OK;
     142             : 
     143           0 :  out:
     144           0 :         TALLOC_FREE(ctx);
     145           0 :         return status;
     146             : }
     147             : 
     148             : /****************************************************************************
     149             :  Delete all streams
     150             : ****************************************************************************/
     151             : 
     152        1432 : NTSTATUS delete_all_streams(connection_struct *conn,
     153             :                         const struct smb_filename *smb_fname)
     154             : {
     155        1432 :         struct stream_struct *stream_info = NULL;
     156             :         unsigned int i;
     157        1432 :         unsigned int num_streams = 0;
     158        1432 :         TALLOC_CTX *frame = talloc_stackframe();
     159             :         NTSTATUS status;
     160             : 
     161        1432 :         status = vfs_fstreaminfo(smb_fname->fsp, talloc_tos(),
     162             :                                 &num_streams, &stream_info);
     163             : 
     164        1432 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
     165           0 :                 DEBUG(10, ("no streams around\n"));
     166           0 :                 TALLOC_FREE(frame);
     167           0 :                 return NT_STATUS_OK;
     168             :         }
     169             : 
     170        1432 :         if (!NT_STATUS_IS_OK(status)) {
     171           0 :                 DEBUG(10, ("vfs_fstreaminfo failed: %s\n",
     172             :                            nt_errstr(status)));
     173           0 :                 goto fail;
     174             :         }
     175             : 
     176        1432 :         DEBUG(10, ("delete_all_streams found %d streams\n",
     177             :                    num_streams));
     178             : 
     179        1432 :         if (num_streams == 0) {
     180         800 :                 TALLOC_FREE(frame);
     181         800 :                 return NT_STATUS_OK;
     182             :         }
     183             : 
     184        1272 :         for (i=0; i<num_streams; i++) {
     185             :                 int res;
     186             :                 struct smb_filename *smb_fname_stream;
     187             : 
     188         640 :                 if (strequal(stream_info[i].name, "::$DATA")) {
     189         624 :                         continue;
     190             :                 }
     191             : 
     192          24 :                 status = synthetic_pathref(talloc_tos(),
     193             :                                            conn->cwd_fsp,
     194          16 :                                            smb_fname->base_name,
     195          16 :                                            stream_info[i].name,
     196             :                                            NULL,
     197           8 :                                            smb_fname->twrp,
     198          16 :                                            (smb_fname->flags &
     199             :                                             ~SMB_FILENAME_POSIX_PATH),
     200             :                                            &smb_fname_stream);
     201          16 :                 if (!NT_STATUS_IS_OK(status)) {
     202           0 :                         DEBUG(0, ("talloc_aprintf failed\n"));
     203           0 :                         status = NT_STATUS_NO_MEMORY;
     204           0 :                         goto fail;
     205             :                 }
     206             : 
     207          16 :                 res = SMB_VFS_UNLINKAT(conn,
     208             :                                 conn->cwd_fsp,
     209             :                                 smb_fname_stream,
     210             :                                 0);
     211             : 
     212          16 :                 if (res == -1) {
     213           0 :                         status = map_nt_error_from_unix(errno);
     214           0 :                         DEBUG(10, ("Could not delete stream %s: %s\n",
     215             :                                    smb_fname_str_dbg(smb_fname_stream),
     216             :                                    strerror(errno)));
     217           0 :                         TALLOC_FREE(smb_fname_stream);
     218           0 :                         break;
     219             :                 }
     220          16 :                 TALLOC_FREE(smb_fname_stream);
     221             :         }
     222             : 
     223         632 :  fail:
     224         632 :         TALLOC_FREE(frame);
     225         632 :         return status;
     226             : }
     227             : 
     228             : struct has_other_nonposix_opens_state {
     229             :         files_struct *fsp;
     230             :         bool found_another;
     231             : };
     232             : 
     233        1369 : static bool has_other_nonposix_opens_fn(
     234             :         struct share_mode_entry *e,
     235             :         bool *modified,
     236             :         void *private_data)
     237             : {
     238        1369 :         struct has_other_nonposix_opens_state *state = private_data;
     239        1369 :         struct files_struct *fsp = state->fsp;
     240             : 
     241        1369 :         if (e->name_hash != fsp->name_hash) {
     242           0 :                 return false;
     243             :         }
     244        1369 :         if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
     245           0 :             (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
     246           0 :                 return false;
     247             :         }
     248        1369 :         if (e->share_file_id == fh_get_gen_id(fsp->fh)) {
     249        1368 :                 struct server_id self = messaging_server_id(
     250        1368 :                         fsp->conn->sconn->msg_ctx);
     251        1368 :                 if (server_id_equal(&self, &e->pid)) {
     252        1368 :                         return false;
     253             :                 }
     254             :         }
     255           1 :         if (share_entry_stale_pid(e)) {
     256           0 :                 return false;
     257             :         }
     258             : 
     259           1 :         state->found_another = true;
     260           1 :         return true;
     261             : }
     262             : 
     263        1369 : bool has_other_nonposix_opens(struct share_mode_lock *lck,
     264             :                               struct files_struct *fsp)
     265             : {
     266        1369 :         struct has_other_nonposix_opens_state state = { .fsp = fsp };
     267             :         bool ok;
     268             : 
     269        1369 :         ok = share_mode_forall_entries(
     270             :                 lck, has_other_nonposix_opens_fn, &state);
     271        1369 :         if (!ok) {
     272           0 :                 return false;
     273             :         }
     274        1369 :         return state.found_another;
     275             : }
     276             : 
     277             : /****************************************************************************
     278             :  Deal with removing a share mode on last close.
     279             : ****************************************************************************/
     280             : 
     281        1850 : static NTSTATUS close_remove_share_mode(files_struct *fsp,
     282             :                                         enum file_close_type close_type)
     283             : {
     284        1850 :         connection_struct *conn = fsp->conn;
     285        1850 :         bool delete_file = false;
     286        1850 :         bool changed_user = false;
     287        1850 :         struct share_mode_lock *lck = NULL;
     288        1850 :         NTSTATUS status = NT_STATUS_OK;
     289             :         NTSTATUS tmp_status;
     290             :         struct file_id id;
     291        1850 :         const struct security_unix_token *del_token = NULL;
     292        1850 :         const struct security_token *del_nt_token = NULL;
     293        1850 :         struct smb_filename *parent_fname = NULL;
     294        1850 :         struct smb_filename *base_fname = NULL;
     295        1850 :         bool got_tokens = false;
     296             :         bool normal_close;
     297             :         int ret;
     298             : 
     299             :         /* Ensure any pending write time updates are done. */
     300        1850 :         if (fsp->update_write_time_event) {
     301         436 :                 fsp_flush_write_time_update(fsp);
     302             :         }
     303             : 
     304             :         /*
     305             :          * Lock the share entries, and determine if we should delete
     306             :          * on close. If so delete whilst the lock is still in effect.
     307             :          * This prevents race conditions with the file being created. JRA.
     308             :          */
     309             : 
     310        1850 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
     311        1850 :         if (lck == NULL) {
     312           0 :                 DEBUG(0, ("close_remove_share_mode: Could not get share mode "
     313             :                           "lock for file %s\n", fsp_str_dbg(fsp)));
     314           0 :                 return NT_STATUS_INVALID_PARAMETER;
     315             :         }
     316             : 
     317             :         /* Remove the oplock before potentially deleting the file. */
     318        1850 :         if(fsp->oplock_type) {
     319         124 :                 remove_oplock(fsp);
     320             :         }
     321             : 
     322        1850 :         if (fsp->fsp_flags.write_time_forced) {
     323           1 :                 NTTIME mtime = share_mode_changed_write_time(lck);
     324           1 :                 struct timespec ts = nt_time_to_full_timespec(mtime);
     325             : 
     326           1 :                 DEBUG(10,("close_remove_share_mode: write time forced "
     327             :                         "for file %s\n",
     328             :                         fsp_str_dbg(fsp)));
     329           1 :                 set_close_write_time(fsp, ts);
     330        1849 :         } else if (fsp->fsp_flags.update_write_time_on_close) {
     331             :                 /* Someone had a pending write. */
     332           0 :                 if (is_omit_timespec(&fsp->close_write_time)) {
     333           0 :                         DEBUG(10,("close_remove_share_mode: update to current time "
     334             :                                 "for file %s\n",
     335             :                                 fsp_str_dbg(fsp)));
     336             :                         /* Update to current time due to "normal" write. */
     337           0 :                         set_close_write_time(fsp, timespec_current());
     338             :                 } else {
     339           0 :                         DEBUG(10,("close_remove_share_mode: write time pending "
     340             :                                 "for file %s\n",
     341             :                                 fsp_str_dbg(fsp)));
     342             :                         /* Update to time set on close call. */
     343           0 :                         set_close_write_time(fsp, fsp->close_write_time);
     344             :                 }
     345             :         }
     346             : 
     347        2314 :         if (fsp->fsp_flags.initial_delete_on_close &&
     348         556 :                         !is_delete_on_close_set(lck, fsp->name_hash)) {
     349             :                 /* Initial delete on close was set and no one else
     350             :                  * wrote a real delete on close. */
     351             : 
     352         556 :                 fsp->fsp_flags.delete_on_close = true;
     353         556 :                 set_delete_on_close_lck(fsp, lck,
     354         556 :                                         fsp->conn->session_info->security_token,
     355         556 :                                         fsp->conn->session_info->unix_token);
     356             :         }
     357             : 
     358        2411 :         delete_file = is_delete_on_close_set(lck, fsp->name_hash) &&
     359         561 :                 !has_other_nonposix_opens(lck, fsp);
     360             : 
     361             :         /*
     362             :          * NT can set delete_on_close of the last open
     363             :          * reference to a file.
     364             :          */
     365             : 
     366        1850 :         normal_close = (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE);
     367             : 
     368        1850 :         if (!normal_close || !delete_file) {
     369        1290 :                 status = NT_STATUS_OK;
     370        1290 :                 goto done;
     371             :         }
     372             : 
     373             :         /*
     374             :          * Ok, we have to delete the file
     375             :          */
     376             : 
     377         560 :         DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
     378             :                  "- deleting file.\n", fsp_str_dbg(fsp)));
     379             : 
     380             :         /*
     381             :          * Don't try to update the write time when we delete the file
     382             :          */
     383         560 :         fsp->fsp_flags.update_write_time_on_close = false;
     384             : 
     385         560 :         got_tokens = get_delete_on_close_token(lck, fsp->name_hash,
     386             :                                         &del_nt_token, &del_token);
     387         560 :         SMB_ASSERT(got_tokens);
     388             : 
     389         560 :         if (!unix_token_equal(del_token, get_current_utok(conn))) {
     390             :                 /* Become the user who requested the delete. */
     391             : 
     392           5 :                 DEBUG(5,("close_remove_share_mode: file %s. "
     393             :                         "Change user to uid %u\n",
     394             :                         fsp_str_dbg(fsp),
     395             :                         (unsigned int)del_token->uid));
     396             : 
     397           5 :                 if (!push_sec_ctx()) {
     398           0 :                         smb_panic("close_remove_share_mode: file %s. failed to push "
     399             :                                   "sec_ctx.\n");
     400             :                 }
     401             : 
     402          14 :                 set_sec_ctx(del_token->uid,
     403           5 :                             del_token->gid,
     404           5 :                             del_token->ngroups,
     405           5 :                             del_token->groups,
     406             :                             del_nt_token);
     407             : 
     408           5 :                 changed_user = true;
     409             :         }
     410             : 
     411             :         /* We can only delete the file if the name we have is still valid and
     412             :            hasn't been renamed. */
     413             : 
     414         560 :         tmp_status = vfs_stat_fsp(fsp);
     415         560 :         if (!NT_STATUS_IS_OK(tmp_status)) {
     416           0 :                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
     417             :                          "was set and stat failed with error %s\n",
     418             :                          fsp_str_dbg(fsp), nt_errstr(tmp_status)));
     419             :                 /*
     420             :                  * Don't save the errno here, we ignore this error
     421             :                  */
     422           0 :                 goto done;
     423             :         }
     424             : 
     425         560 :         id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     426             : 
     427         560 :         if (!file_id_equal(&fsp->file_id, &id)) {
     428             :                 struct file_id_buf ftmp1, ftmp2;
     429           0 :                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
     430             :                          "was set and dev and/or inode does not match\n",
     431             :                          fsp_str_dbg(fsp)));
     432           0 :                 DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
     433             :                          "stat file_id %s\n",
     434             :                          fsp_str_dbg(fsp),
     435             :                          file_id_str_buf(fsp->file_id, &ftmp1),
     436             :                          file_id_str_buf(id, &ftmp2)));
     437             :                 /*
     438             :                  * Don't save the errno here, we ignore this error
     439             :                  */
     440           0 :                 goto done;
     441             :         }
     442             : 
     443         560 :         if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
     444         560 :             && !fsp_is_alternate_stream(fsp)) {
     445             : 
     446         560 :                 status = delete_all_streams(conn, fsp->fsp_name);
     447             : 
     448         560 :                 if (!NT_STATUS_IS_OK(status)) {
     449           0 :                         DEBUG(5, ("delete_all_streams failed: %s\n",
     450             :                                   nt_errstr(status)));
     451           0 :                         goto done;
     452             :                 }
     453             :         }
     454             : 
     455         560 :         if (fsp->fsp_flags.kernel_share_modes_taken) {
     456             :                 /*
     457             :                  * A file system sharemode could block the unlink;
     458             :                  * remove filesystem sharemodes first.
     459             :                  */
     460           0 :                 ret = SMB_VFS_FILESYSTEM_SHAREMODE(fsp, 0, 0);
     461           0 :                 if (ret == -1) {
     462           0 :                         DBG_INFO("Removing file system sharemode for %s "
     463             :                                  "failed: %s\n",
     464             :                                  fsp_str_dbg(fsp), strerror(errno));
     465             :                 }
     466             : 
     467           0 :                 fsp->fsp_flags.kernel_share_modes_taken = false;
     468             :         }
     469             : 
     470         560 :         status = parent_pathref(talloc_tos(),
     471             :                                 conn->cwd_fsp,
     472         560 :                                 fsp->fsp_name,
     473             :                                 &parent_fname,
     474             :                                 &base_fname);
     475         560 :         if (!NT_STATUS_IS_OK(status)) {
     476           0 :                 goto done;
     477             :         }
     478             : 
     479         560 :         ret = SMB_VFS_UNLINKAT(conn,
     480             :                                parent_fname->fsp,
     481             :                                base_fname,
     482             :                                0);
     483         560 :         TALLOC_FREE(parent_fname);
     484         560 :         base_fname = NULL;
     485         560 :         if (ret != 0) {
     486             :                 /*
     487             :                  * This call can potentially fail as another smbd may
     488             :                  * have had the file open with delete on close set and
     489             :                  * deleted it when its last reference to this file
     490             :                  * went away. Hence we log this but not at debug level
     491             :                  * zero.
     492             :                  */
     493             : 
     494           0 :                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
     495             :                          "was set and unlink failed with error %s\n",
     496             :                          fsp_str_dbg(fsp), strerror(errno)));
     497             : 
     498           0 :                 status = map_nt_error_from_unix(errno);
     499             :         }
     500             : 
     501             :         /* As we now have POSIX opens which can unlink
     502             :          * with other open files we may have taken
     503             :          * this code path with more than one share mode
     504             :          * entry - ensure we only delete once by resetting
     505             :          * the delete on close flag. JRA.
     506             :          */
     507             : 
     508         560 :         fsp->fsp_flags.delete_on_close = false;
     509         560 :         reset_delete_on_close_lck(fsp, lck);
     510             : 
     511        1850 :  done:
     512             : 
     513        1850 :         if (changed_user) {
     514             :                 /* unbecome user. */
     515           5 :                 pop_sec_ctx();
     516             :         }
     517             : 
     518        1850 :         if (fsp->fsp_flags.kernel_share_modes_taken) {
     519             :                 /* remove filesystem sharemodes */
     520           0 :                 ret = SMB_VFS_FILESYSTEM_SHAREMODE(fsp, 0, 0);
     521           0 :                 if (ret == -1) {
     522           0 :                         DBG_INFO("Removing file system sharemode for "
     523             :                                  "%s failed: %s\n",
     524             :                                  fsp_str_dbg(fsp), strerror(errno));
     525             :                 }
     526             :         }
     527             : 
     528        1850 :         if (!del_share_mode(lck, fsp)) {
     529           0 :                 DEBUG(0, ("close_remove_share_mode: Could not delete share "
     530             :                           "entry for file %s\n", fsp_str_dbg(fsp)));
     531             :         }
     532             : 
     533        1850 :         TALLOC_FREE(lck);
     534             : 
     535        1850 :         if (delete_file) {
     536             :                 /*
     537             :                  * Do the notification after we released the share
     538             :                  * mode lock. Inside notify_fname we take out another
     539             :                  * tdb lock. With ctdb also accessing our databases,
     540             :                  * this can lead to deadlocks. Putting this notify
     541             :                  * after the TALLOC_FREE(lck) above we avoid locking
     542             :                  * two records simultaneously. Notifies are async and
     543             :                  * informational only, so calling the notify_fname
     544             :                  * without holding the share mode lock should not do
     545             :                  * any harm.
     546             :                  */
     547         560 :                 notify_fname(conn, NOTIFY_ACTION_REMOVED,
     548             :                              FILE_NOTIFY_CHANGE_FILE_NAME,
     549         560 :                              fsp->fsp_name->base_name);
     550             :         }
     551             : 
     552        1850 :         return status;
     553             : }
     554             : 
     555           1 : void set_close_write_time(struct files_struct *fsp, struct timespec ts)
     556             : {
     557           1 :         DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
     558             : 
     559           1 :         if (is_omit_timespec(&ts)) {
     560           0 :                 return;
     561             :         }
     562           1 :         fsp->fsp_flags.write_time_forced = false;
     563           1 :         fsp->fsp_flags.update_write_time_on_close = true;
     564           1 :         fsp->close_write_time = ts;
     565             : }
     566             : 
     567        1850 : static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
     568             : {
     569             :         struct smb_file_time ft;
     570             :         NTSTATUS status;
     571        1850 :         struct share_mode_lock *lck = NULL;
     572             : 
     573        1850 :         init_smb_file_time(&ft);
     574             : 
     575        1850 :         if (!(fsp->fsp_flags.update_write_time_on_close)) {
     576        1849 :                 return NT_STATUS_OK;
     577             :         }
     578             : 
     579           1 :         if (is_omit_timespec(&fsp->close_write_time)) {
     580           0 :                 fsp->close_write_time = timespec_current();
     581             :         }
     582             : 
     583             :         /* Ensure we have a valid stat struct for the source. */
     584           1 :         status = vfs_stat_fsp(fsp);
     585           1 :         if (!NT_STATUS_IS_OK(status)) {
     586           0 :                 return status;
     587             :         }
     588             : 
     589           1 :         if (!VALID_STAT(fsp->fsp_name->st)) {
     590             :                 /* if it doesn't seem to be a real file */
     591           0 :                 return NT_STATUS_OK;
     592             :         }
     593             : 
     594             :         /*
     595             :          * get_existing_share_mode_lock() isn't really the right
     596             :          * call here, as we're being called after
     597             :          * close_remove_share_mode() inside close_normal_file()
     598             :          * so it's quite normal to not have an existing share
     599             :          * mode here. However, get_share_mode_lock() doesn't
     600             :          * work because that will create a new share mode if
     601             :          * one doesn't exist - so stick with this call (just
     602             :          * ignore any error we get if the share mode doesn't
     603             :          * exist.
     604             :          */
     605             : 
     606           1 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
     607           1 :         if (lck) {
     608           0 :                 NTTIME share_mtime = share_mode_changed_write_time(lck);
     609             :                 /* On close if we're changing the real file time we
     610             :                  * must update it in the open file db too. */
     611           0 :                 (void)set_write_time(fsp->file_id, fsp->close_write_time);
     612             : 
     613             :                 /* Close write times overwrite sticky write times
     614             :                    so we must replace any sticky write time here. */
     615           0 :                 if (!null_nttime(share_mtime)) {
     616           0 :                         (void)set_sticky_write_time(fsp->file_id, fsp->close_write_time);
     617             :                 }
     618           0 :                 TALLOC_FREE(lck);
     619             :         }
     620             : 
     621           1 :         ft.mtime = fsp->close_write_time;
     622             :         /* As this is a close based update, we are not directly changing the
     623             :            file attributes from a client call, but indirectly from a write. */
     624           1 :         status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
     625           1 :         if (!NT_STATUS_IS_OK(status)) {
     626           0 :                 DEBUG(10,("update_write_time_on_close: smb_set_file_time "
     627             :                         "on file %s returned %s\n",
     628             :                         fsp_str_dbg(fsp),
     629             :                         nt_errstr(status)));
     630           0 :                 return status;
     631             :         }
     632             : 
     633           1 :         return status;
     634             : }
     635             : 
     636        7388 : static NTSTATUS ntstatus_keeperror(NTSTATUS s1, NTSTATUS s2)
     637             : {
     638        7388 :         if (!NT_STATUS_IS_OK(s1)) {
     639           0 :                 return s1;
     640             :         }
     641        7388 :         return s2;
     642             : }
     643             : 
     644       12066 : static void assert_no_pending_aio(struct files_struct *fsp,
     645             :                                   enum file_close_type close_type)
     646             : {
     647       12066 :         struct smbXsrv_client *client = global_smbXsrv_client;
     648             :         size_t num_connections_alive;
     649       12066 :         unsigned num_requests = fsp->num_aio_requests;
     650             : 
     651       12066 :         if (num_requests == 0) {
     652       12066 :                 return;
     653             :         }
     654             : 
     655           0 :         num_connections_alive = smbXsrv_client_valid_connections(client);
     656             : 
     657           0 :         if (close_type == SHUTDOWN_CLOSE && num_connections_alive == 0) {
     658             :                 /*
     659             :                  * fsp->aio_requests and the contents (fsp->aio_requests[x])
     660             :                  * are both independently owned by fsp and are not in a
     661             :                  * talloc heirarchy. This allows the fsp->aio_requests array to
     662             :                  * be reallocated independently of the array contents so it can
     663             :                  * grow on demand.
     664             :                  *
     665             :                  * This means we must ensure order of deallocation
     666             :                  * on a SHUTDOWN_CLOSE by deallocating the fsp->aio_requests[x]
     667             :                  * contents first, as their destructors access the
     668             :                  * fsp->aio_request array. If we don't deallocate them
     669             :                  * first, when fsp is deallocated fsp->aio_requests
     670             :                  * could have been deallocated *before* its contents
     671             :                  * fsp->aio_requests[x], causing a crash.
     672             :                  */
     673           0 :                 while (fsp->num_aio_requests != 0) {
     674             :                         /*
     675             :                          * NB. We *MUST* use
     676             :                          * talloc_free(fsp->aio_requests[0]),
     677             :                          * and *NOT* TALLOC_FREE() here, as
     678             :                          * TALLOC_FREE(fsp->aio_requests[0])
     679             :                          * will overwrite any new contents of
     680             :                          * fsp->aio_requests[0] that were
     681             :                          * copied into it via the destructor
     682             :                          * aio_del_req_from_fsp().
     683             :                          *
     684             :                          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14515
     685             :                          */
     686           0 :                         talloc_free(fsp->aio_requests[0]);
     687             :                 }
     688           0 :                 return;
     689             :         }
     690             : 
     691           0 :         DBG_ERR("fsp->num_aio_requests=%u\n", num_requests);
     692           0 :         smb_panic("can not close with outstanding aio requests");
     693             :         return;
     694             : }
     695             : 
     696             : /****************************************************************************
     697             :  Close a file.
     698             : 
     699             :  close_type can be NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE.
     700             :  printing and magic scripts are only run on normal close.
     701             :  delete on close is done on normal and shutdown close.
     702             : ****************************************************************************/
     703             : 
     704        1850 : static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
     705             :                                   enum file_close_type close_type)
     706             : {
     707        1850 :         NTSTATUS status = NT_STATUS_OK;
     708             :         NTSTATUS tmp;
     709        1850 :         connection_struct *conn = fsp->conn;
     710        1850 :         bool is_durable = false;
     711             : 
     712        1850 :         SMB_ASSERT(fsp->fsp_flags.is_fsa);
     713             : 
     714        1850 :         assert_no_pending_aio(fsp, close_type);
     715             : 
     716        3410 :         while (talloc_array_length(fsp->blocked_smb1_lock_reqs) != 0) {
     717           0 :                 smbd_smb1_brl_finish_by_req(
     718           0 :                         fsp->blocked_smb1_lock_reqs[0],
     719           0 :                         NT_STATUS_RANGE_NOT_LOCKED);
     720             :         }
     721             : 
     722             :         /*
     723             :          * If we're flushing on a close we can get a write
     724             :          * error here, we must remember this.
     725             :          */
     726             : 
     727        1850 :         if (NT_STATUS_IS_OK(status) && fsp->op != NULL) {
     728        1818 :                 is_durable = fsp->op->global->durable;
     729             :         }
     730             : 
     731        1850 :         if (close_type != SHUTDOWN_CLOSE) {
     732        1838 :                 is_durable = false;
     733             :         }
     734             : 
     735        1850 :         if (is_durable) {
     736           0 :                 DATA_BLOB new_cookie = data_blob_null;
     737             : 
     738           0 :                 tmp = SMB_VFS_DURABLE_DISCONNECT(fsp,
     739             :                                         fsp->op->global->backend_cookie,
     740             :                                         fsp->op,
     741             :                                         &new_cookie);
     742           0 :                 if (NT_STATUS_IS_OK(tmp)) {
     743             :                         struct timeval tv;
     744             :                         NTTIME now;
     745             : 
     746           0 :                         if (req != NULL) {
     747           0 :                                 tv = req->request_time;
     748             :                         } else {
     749           0 :                                 tv = timeval_current();
     750             :                         }
     751           0 :                         now = timeval_to_nttime(&tv);
     752             : 
     753           0 :                         data_blob_free(&fsp->op->global->backend_cookie);
     754           0 :                         fsp->op->global->backend_cookie = new_cookie;
     755             : 
     756           0 :                         fsp->op->compat = NULL;
     757           0 :                         tmp = smbXsrv_open_close(fsp->op, now);
     758           0 :                         if (!NT_STATUS_IS_OK(tmp)) {
     759           0 :                                 DEBUG(1, ("Failed to update smbXsrv_open "
     760             :                                           "record when disconnecting durable "
     761             :                                           "handle for file %s: %s - "
     762             :                                           "proceeding with normal close\n",
     763             :                                           fsp_str_dbg(fsp), nt_errstr(tmp)));
     764             :                         }
     765           0 :                         scavenger_schedule_disconnected(fsp);
     766             :                 } else {
     767           0 :                         DEBUG(1, ("Failed to disconnect durable handle for "
     768             :                                   "file %s: %s - proceeding with normal "
     769             :                                   "close\n", fsp_str_dbg(fsp), nt_errstr(tmp)));
     770             :                 }
     771           0 :                 if (!NT_STATUS_IS_OK(tmp)) {
     772           0 :                         is_durable = false;
     773             :                 }
     774             :         }
     775             : 
     776        1850 :         if (is_durable) {
     777             :                 /*
     778             :                  * This is the case where we successfully disconnected
     779             :                  * a durable handle and closed the underlying file.
     780             :                  * In all other cases, we proceed with a genuine close.
     781             :                  */
     782           0 :                 DEBUG(10, ("%s disconnected durable handle for file %s\n",
     783             :                            conn->session_info->unix_info->unix_name,
     784             :                            fsp_str_dbg(fsp)));
     785           0 :                 return NT_STATUS_OK;
     786             :         }
     787             : 
     788        1850 :         if (fsp->op != NULL) {
     789             :                 /*
     790             :                  * Make sure the handle is not marked as durable anymore
     791             :                  */
     792        1818 :                 fsp->op->global->durable = false;
     793             :         }
     794             : 
     795             :         /* If this is an old DOS or FCB open and we have multiple opens on
     796             :            the same handle we only have one share mode. Ensure we only remove
     797             :            the share mode on the last close. */
     798             : 
     799        1850 :         if (fh_get_refcount(fsp->fh) == 1) {
     800             :                 /* Should we return on error here... ? */
     801        1850 :                 tmp = close_remove_share_mode(fsp, close_type);
     802        1850 :                 status = ntstatus_keeperror(status, tmp);
     803             :         }
     804             : 
     805        1850 :         locking_close_file(fsp, close_type);
     806             : 
     807             :         /*
     808             :          * Ensure pending modtime is set before closing underlying fd.
     809             :          */
     810             : 
     811        1850 :         tmp = update_write_time_on_close(fsp);
     812        1850 :         if (NT_STATUS_EQUAL(tmp, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
     813             :                 /*
     814             :                  * Someone renamed the file or a parent directory containing
     815             :                  * this file. We can't do anything about this, eat the error.
     816             :                  */
     817           0 :                 tmp = NT_STATUS_OK;
     818             :         }
     819        1850 :         status = ntstatus_keeperror(status, tmp);
     820             : 
     821        1850 :         tmp = fd_close(fsp);
     822        1850 :         status = ntstatus_keeperror(status, tmp);
     823             : 
     824             :         /* check for magic scripts */
     825        1850 :         if (close_type == NORMAL_CLOSE) {
     826        1838 :                 tmp = check_magic(fsp);
     827        1838 :                 status = ntstatus_keeperror(status, tmp);
     828             :         }
     829             : 
     830        1850 :         DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
     831             :                 conn->session_info->unix_info->unix_name, fsp_str_dbg(fsp),
     832             :                 conn->num_files_open - 1,
     833             :                 nt_errstr(status) ));
     834             : 
     835        1850 :         return status;
     836             : }
     837             : /****************************************************************************
     838             :  Function used by reply_rmdir to delete an entire directory
     839             :  tree recursively. Return True on ok, False on fail.
     840             : ****************************************************************************/
     841             : 
     842           0 : NTSTATUS recursive_rmdir(TALLOC_CTX *ctx,
     843             :                      connection_struct *conn,
     844             :                      struct smb_filename *smb_dname)
     845             : {
     846           0 :         const char *dname = NULL;
     847           0 :         char *talloced = NULL;
     848           0 :         long offset = 0;
     849             :         SMB_STRUCT_STAT st;
     850           0 :         struct smb_Dir *dir_hnd = NULL;
     851           0 :         struct files_struct *dirfsp = NULL;
     852             :         int retval;
     853           0 :         NTSTATUS status = NT_STATUS_OK;
     854             : 
     855           0 :         SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
     856             : 
     857           0 :         status = OpenDir(talloc_tos(),
     858             :                          conn,
     859             :                          smb_dname,
     860             :                          NULL,
     861             :                          0,
     862             :                          &dir_hnd);
     863           0 :         if (!NT_STATUS_IS_OK(status)) {
     864           0 :                 return status;
     865             :         }
     866             : 
     867           0 :         dirfsp = dir_hnd_fetch_fsp(dir_hnd);
     868             : 
     869           0 :         while ((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) {
     870           0 :                 struct smb_filename *atname = NULL;
     871           0 :                 struct smb_filename *smb_dname_full = NULL;
     872           0 :                 char *fullname = NULL;
     873           0 :                 bool do_break = true;
     874           0 :                 int unlink_flags = 0;
     875             : 
     876           0 :                 if (ISDOT(dname) || ISDOTDOT(dname)) {
     877           0 :                         TALLOC_FREE(talloced);
     878           0 :                         continue;
     879             :                 }
     880             : 
     881             :                 /* Construct the full name. */
     882           0 :                 fullname = talloc_asprintf(ctx,
     883             :                                 "%s/%s",
     884             :                                 smb_dname->base_name,
     885             :                                 dname);
     886           0 :                 if (!fullname) {
     887           0 :                         status = NT_STATUS_NO_MEMORY;
     888           0 :                         goto err_break;
     889             :                 }
     890             : 
     891           0 :                 smb_dname_full = synthetic_smb_fname(talloc_tos(),
     892             :                                                 fullname,
     893             :                                                 NULL,
     894             :                                                 NULL,
     895             :                                                 smb_dname->twrp,
     896             :                                                 smb_dname->flags);
     897           0 :                 if (smb_dname_full == NULL) {
     898           0 :                         status = NT_STATUS_NO_MEMORY;
     899           0 :                         goto err_break;
     900             :                 }
     901             : 
     902           0 :                 if (SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
     903           0 :                         status = map_nt_error_from_unix(errno);
     904           0 :                         goto err_break;
     905             :                 }
     906             : 
     907           0 :                 if (smb_dname_full->st.st_ex_mode & S_IFDIR) {
     908           0 :                         status = recursive_rmdir(ctx, conn, smb_dname_full);
     909           0 :                         if (!NT_STATUS_IS_OK(status)) {
     910           0 :                                 goto err_break;
     911             :                         }
     912           0 :                         unlink_flags = AT_REMOVEDIR;
     913             :                 }
     914             : 
     915           0 :                 status = synthetic_pathref(talloc_tos(),
     916             :                                            dirfsp,
     917             :                                            dname,
     918             :                                            NULL,
     919           0 :                                            &smb_dname_full->st,
     920             :                                            smb_dname_full->twrp,
     921             :                                            smb_dname_full->flags,
     922             :                                            &atname);
     923           0 :                 if (!NT_STATUS_IS_OK(status)) {
     924           0 :                         goto err_break;
     925             :                 }
     926             : 
     927           0 :                 if (!is_visible_fsp(atname->fsp)) {
     928           0 :                         TALLOC_FREE(smb_dname_full);
     929           0 :                         TALLOC_FREE(fullname);
     930           0 :                         TALLOC_FREE(talloced);
     931           0 :                         TALLOC_FREE(atname);
     932           0 :                         continue;
     933             :                 }
     934             : 
     935           0 :                 retval = SMB_VFS_UNLINKAT(conn,
     936             :                                           dirfsp,
     937             :                                           atname,
     938             :                                           unlink_flags);
     939           0 :                 if (retval != 0) {
     940           0 :                         status = map_nt_error_from_unix(errno);
     941           0 :                         goto err_break;
     942             :                 }
     943             : 
     944             :                 /* Successful iteration. */
     945           0 :                 do_break = false;
     946             : 
     947           0 :          err_break:
     948           0 :                 TALLOC_FREE(smb_dname_full);
     949           0 :                 TALLOC_FREE(fullname);
     950           0 :                 TALLOC_FREE(talloced);
     951           0 :                 TALLOC_FREE(atname);
     952           0 :                 if (do_break) {
     953           0 :                         break;
     954             :                 }
     955             :         }
     956           0 :         TALLOC_FREE(dir_hnd);
     957           0 :         return status;
     958             : }
     959             : 
     960             : /****************************************************************************
     961             :  The internals of the rmdir code - called elsewhere.
     962             : ****************************************************************************/
     963             : 
     964         808 : static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp)
     965             : {
     966         808 :         struct connection_struct *conn = fsp->conn;
     967         808 :         struct smb_filename *smb_dname = fsp->fsp_name;
     968         808 :         struct smb_filename *parent_fname = NULL;
     969         808 :         struct smb_filename *at_fname = NULL;
     970             :         SMB_STRUCT_STAT st;
     971         808 :         const char *dname = NULL;
     972         808 :         char *talloced = NULL;
     973         808 :         long dirpos = 0;
     974         808 :         struct smb_Dir *dir_hnd = NULL;
     975         808 :         struct files_struct *dirfsp = NULL;
     976         808 :         int unlink_flags = 0;
     977             :         NTSTATUS status;
     978             :         int ret;
     979             : 
     980         808 :         SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
     981             : 
     982         808 :         status = parent_pathref(talloc_tos(),
     983             :                                 conn->cwd_fsp,
     984         808 :                                 fsp->fsp_name,
     985             :                                 &parent_fname,
     986             :                                 &at_fname);
     987         808 :         if (!NT_STATUS_IS_OK(status)) {
     988           0 :                 return status;
     989             :         }
     990             : 
     991             :         /*
     992             :          * Todo: use SMB_VFS_STATX() once it's available.
     993             :          */
     994             : 
     995             :         /* Might be a symlink. */
     996         808 :         ret = SMB_VFS_LSTAT(conn, smb_dname);
     997         808 :         if (ret != 0) {
     998           0 :                 TALLOC_FREE(parent_fname);
     999           0 :                 return map_nt_error_from_unix(errno);
    1000             :         }
    1001             : 
    1002         808 :         if (S_ISLNK(smb_dname->st.st_ex_mode)) {
    1003             :                 /* Is what it points to a directory ? */
    1004           0 :                 ret = SMB_VFS_STAT(conn, smb_dname);
    1005           0 :                 if (ret != 0) {
    1006           0 :                         TALLOC_FREE(parent_fname);
    1007           0 :                         return map_nt_error_from_unix(errno);
    1008             :                 }
    1009           0 :                 if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
    1010           0 :                         TALLOC_FREE(parent_fname);
    1011           0 :                         return NT_STATUS_NOT_A_DIRECTORY;
    1012             :                 }
    1013             :         } else {
    1014         808 :                 unlink_flags = AT_REMOVEDIR;
    1015             :         }
    1016             : 
    1017         808 :         ret = SMB_VFS_UNLINKAT(conn,
    1018             :                                parent_fname->fsp,
    1019             :                                at_fname,
    1020             :                                unlink_flags);
    1021         808 :         if (ret == 0) {
    1022         808 :                 TALLOC_FREE(parent_fname);
    1023         808 :                 notify_fname(conn, NOTIFY_ACTION_REMOVED,
    1024             :                              FILE_NOTIFY_CHANGE_DIR_NAME,
    1025         808 :                              smb_dname->base_name);
    1026         808 :                 return NT_STATUS_OK;
    1027             :         }
    1028             : 
    1029           0 :         if (!((errno == ENOTEMPTY) || (errno == EEXIST))) {
    1030           0 :                 DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
    1031             :                          "%s\n", smb_fname_str_dbg(smb_dname),
    1032             :                          strerror(errno)));
    1033           0 :                 TALLOC_FREE(parent_fname);
    1034           0 :                 return map_nt_error_from_unix(errno);
    1035             :         }
    1036             : 
    1037             :         /*
    1038             :          * Here we know the initial directory unlink failed with
    1039             :          * ENOTEMPTY or EEXIST so we know there are objects within.
    1040             :          * If we don't have permission to delete files non
    1041             :          * visible to the client just fail the directory delete.
    1042             :          */
    1043             : 
    1044           0 :         if (!lp_delete_veto_files(SNUM(conn))) {
    1045           0 :                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1046           0 :                 goto err;
    1047             :         }
    1048             : 
    1049             :         /*
    1050             :          * Check to see if the only thing in this directory are
    1051             :          * files non-visible to the client. If not, fail the delete.
    1052             :          */
    1053             : 
    1054           0 :         status = OpenDir(talloc_tos(),
    1055             :                          conn,
    1056             :                          smb_dname,
    1057             :                          NULL,
    1058             :                          0,
    1059             :                          &dir_hnd);
    1060           0 :         if (!NT_STATUS_IS_OK(status)) {
    1061             :                 /*
    1062             :                  * Note, we deliberately squash the error here
    1063             :                  * to avoid leaking information about what we
    1064             :                  * can't delete.
    1065             :                  */
    1066           0 :                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1067           0 :                 goto err;
    1068             :         }
    1069             : 
    1070           0 :         dirfsp = dir_hnd_fetch_fsp(dir_hnd);
    1071             : 
    1072           0 :         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) {
    1073           0 :                 struct smb_filename *smb_dname_full = NULL;
    1074           0 :                 struct smb_filename *direntry_fname = NULL;
    1075           0 :                 char *fullname = NULL;
    1076             :                 int retval;
    1077             : 
    1078           0 :                 if (ISDOT(dname) || ISDOTDOT(dname)) {
    1079           0 :                         TALLOC_FREE(talloced);
    1080           0 :                         continue;
    1081             :                 }
    1082           0 :                 if (IS_VETO_PATH(conn, dname)) {
    1083           0 :                         TALLOC_FREE(talloced);
    1084           0 :                         continue;
    1085             :                 }
    1086             : 
    1087           0 :                 fullname = talloc_asprintf(talloc_tos(),
    1088             :                                            "%s/%s",
    1089             :                                            smb_dname->base_name,
    1090             :                                            dname);
    1091             : 
    1092           0 :                 if (fullname == NULL) {
    1093           0 :                         TALLOC_FREE(talloced);
    1094           0 :                         status = NT_STATUS_NO_MEMORY;
    1095           0 :                         goto err;
    1096             :                 }
    1097             : 
    1098           0 :                 smb_dname_full = synthetic_smb_fname(talloc_tos(),
    1099             :                                                      fullname,
    1100             :                                                      NULL,
    1101             :                                                      NULL,
    1102             :                                                      smb_dname->twrp,
    1103             :                                                      smb_dname->flags);
    1104           0 :                 if (smb_dname_full == NULL) {
    1105           0 :                         TALLOC_FREE(talloced);
    1106           0 :                         TALLOC_FREE(fullname);
    1107           0 :                         status = NT_STATUS_NO_MEMORY;
    1108           0 :                         goto err;
    1109             :                 }
    1110             : 
    1111           0 :                 retval = SMB_VFS_LSTAT(conn, smb_dname_full);
    1112           0 :                 if (retval != 0) {
    1113           0 :                         status = map_nt_error_from_unix(errno);
    1114           0 :                         TALLOC_FREE(talloced);
    1115           0 :                         TALLOC_FREE(fullname);
    1116           0 :                         TALLOC_FREE(smb_dname_full);
    1117           0 :                         goto err;
    1118             :                 }
    1119             : 
    1120           0 :                 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
    1121             :                         /* Could it be an msdfs link ? */
    1122           0 :                         if (lp_host_msdfs() &&
    1123           0 :                             lp_msdfs_root(SNUM(conn))) {
    1124             :                                 struct smb_filename *smb_atname;
    1125           0 :                                 smb_atname = synthetic_smb_fname(talloc_tos(),
    1126             :                                                         dname,
    1127             :                                                         NULL,
    1128           0 :                                                         &smb_dname_full->st,
    1129           0 :                                                         fsp->fsp_name->twrp,
    1130           0 :                                                         fsp->fsp_name->flags);
    1131           0 :                                 if (smb_atname == NULL) {
    1132           0 :                                         TALLOC_FREE(talloced);
    1133           0 :                                         TALLOC_FREE(fullname);
    1134           0 :                                         TALLOC_FREE(smb_dname_full);
    1135           0 :                                         status = NT_STATUS_NO_MEMORY;
    1136           0 :                                         goto err;
    1137             :                                 }
    1138           0 :                                 if (is_msdfs_link(fsp, smb_atname)) {
    1139           0 :                                         TALLOC_FREE(talloced);
    1140           0 :                                         TALLOC_FREE(fullname);
    1141           0 :                                         TALLOC_FREE(smb_dname_full);
    1142           0 :                                         TALLOC_FREE(smb_atname);
    1143           0 :                                         DBG_DEBUG("got msdfs link name %s "
    1144             :                                                 "- can't delete directory %s\n",
    1145             :                                                 dname,
    1146             :                                                 fsp_str_dbg(fsp));
    1147           0 :                                         status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1148           0 :                                         goto err;
    1149             :                                 }
    1150           0 :                                 TALLOC_FREE(smb_atname);
    1151             :                         }
    1152             : 
    1153             :                         /* Not a DFS link - could it be a dangling symlink ? */
    1154           0 :                         retval = SMB_VFS_STAT(conn, smb_dname_full);
    1155           0 :                         if (retval == -1 && (errno == ENOENT || errno == ELOOP)) {
    1156             :                                 /*
    1157             :                                  * Dangling symlink.
    1158             :                                  * Allow delete as "delete veto files = yes"
    1159             :                                  */
    1160           0 :                                 TALLOC_FREE(talloced);
    1161           0 :                                 TALLOC_FREE(fullname);
    1162           0 :                                 TALLOC_FREE(smb_dname_full);
    1163           0 :                                 continue;
    1164             :                         }
    1165             : 
    1166           0 :                         DBG_DEBUG("got symlink name %s - "
    1167             :                                 "can't delete directory %s\n",
    1168             :                                 dname,
    1169             :                                 fsp_str_dbg(fsp));
    1170           0 :                         TALLOC_FREE(talloced);
    1171           0 :                         TALLOC_FREE(fullname);
    1172           0 :                         TALLOC_FREE(smb_dname_full);
    1173           0 :                         status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1174           0 :                         goto err;
    1175             :                 }
    1176             : 
    1177             :                 /* Not a symlink, get a pathref. */
    1178           0 :                 status = synthetic_pathref(talloc_tos(),
    1179             :                                            dirfsp,
    1180             :                                            dname,
    1181             :                                            NULL,
    1182           0 :                                            &smb_dname_full->st,
    1183             :                                            smb_dname->twrp,
    1184             :                                            smb_dname->flags,
    1185             :                                            &direntry_fname);
    1186           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1187           0 :                         TALLOC_FREE(talloced);
    1188           0 :                         TALLOC_FREE(fullname);
    1189           0 :                         TALLOC_FREE(smb_dname_full);
    1190           0 :                         goto err;
    1191             :                 }
    1192             : 
    1193           0 :                 if (!is_visible_fsp(direntry_fname->fsp)) {
    1194           0 :                         TALLOC_FREE(talloced);
    1195           0 :                         TALLOC_FREE(fullname);
    1196           0 :                         TALLOC_FREE(smb_dname_full);
    1197           0 :                         TALLOC_FREE(direntry_fname);
    1198           0 :                         continue;
    1199             :                 }
    1200             : 
    1201             :                 /*
    1202             :                  * We found a client visible name.
    1203             :                  * We cannot delete this directory.
    1204             :                  */
    1205           0 :                 DBG_DEBUG("got name %s - "
    1206             :                         "can't delete directory %s\n",
    1207             :                         dname,
    1208             :                         fsp_str_dbg(fsp));
    1209           0 :                 TALLOC_FREE(talloced);
    1210           0 :                 TALLOC_FREE(fullname);
    1211           0 :                 TALLOC_FREE(smb_dname_full);
    1212           0 :                 TALLOC_FREE(direntry_fname);
    1213           0 :                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
    1214           0 :                 goto err;
    1215             :         }
    1216             : 
    1217             :         /* Do a recursive delete. */
    1218           0 :         RewindDir(dir_hnd,&dirpos);
    1219             : 
    1220           0 :         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) {
    1221           0 :                 struct smb_filename *direntry_fname = NULL;
    1222           0 :                 struct smb_filename *smb_dname_full = NULL;
    1223           0 :                 char *fullname = NULL;
    1224           0 :                 bool do_break = true;
    1225             :                 int retval;
    1226             : 
    1227           0 :                 if (ISDOT(dname) || ISDOTDOT(dname)) {
    1228           0 :                         TALLOC_FREE(talloced);
    1229           0 :                         continue;
    1230             :                 }
    1231             : 
    1232           0 :                 fullname = talloc_asprintf(ctx,
    1233             :                                            "%s/%s",
    1234             :                                            smb_dname->base_name,
    1235             :                                            dname);
    1236             : 
    1237           0 :                 if (fullname == NULL) {
    1238           0 :                         status = NT_STATUS_NO_MEMORY;
    1239           0 :                         goto err_break;
    1240             :                 }
    1241             : 
    1242           0 :                 smb_dname_full = synthetic_smb_fname(talloc_tos(),
    1243             :                                                      fullname,
    1244             :                                                      NULL,
    1245             :                                                      NULL,
    1246             :                                                      smb_dname->twrp,
    1247             :                                                      smb_dname->flags);
    1248           0 :                 if (smb_dname_full == NULL) {
    1249           0 :                         status = NT_STATUS_NO_MEMORY;
    1250           0 :                         goto err_break;
    1251             :                 }
    1252             : 
    1253             :                 /*
    1254             :                  * Todo: use SMB_VFS_STATX() once that's available.
    1255             :                  */
    1256             : 
    1257           0 :                 retval = SMB_VFS_LSTAT(conn, smb_dname_full);
    1258           0 :                 if (retval != 0) {
    1259           0 :                         status = map_nt_error_from_unix(errno);
    1260           0 :                         goto err_break;
    1261             :                 }
    1262             : 
    1263             :                 /*
    1264             :                  * We are only dealing with VETO'ed objects
    1265             :                  * here. If it's a symlink, just delete the
    1266             :                  * link without caring what it is pointing
    1267             :                  * to.
    1268             :                  */
    1269           0 :                 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
    1270           0 :                         direntry_fname = synthetic_smb_fname(talloc_tos(),
    1271             :                                                         dname,
    1272             :                                                         NULL,
    1273           0 :                                                         &smb_dname_full->st,
    1274             :                                                         smb_dname->twrp,
    1275             :                                                         smb_dname->flags);
    1276           0 :                         if (direntry_fname == NULL) {
    1277           0 :                                 status = NT_STATUS_NO_MEMORY;
    1278           0 :                                 goto err_break;
    1279             :                         }
    1280             :                 } else {
    1281           0 :                         status = synthetic_pathref(talloc_tos(),
    1282             :                                                    dirfsp,
    1283             :                                                    dname,
    1284             :                                                    NULL,
    1285           0 :                                                    &smb_dname_full->st,
    1286             :                                                    smb_dname->twrp,
    1287             :                                                    smb_dname->flags,
    1288             :                                                    &direntry_fname);
    1289           0 :                         if (!NT_STATUS_IS_OK(status)) {
    1290           0 :                                 goto err_break;
    1291             :                         }
    1292             : 
    1293           0 :                         if (!is_visible_fsp(direntry_fname->fsp)) {
    1294           0 :                                 TALLOC_FREE(fullname);
    1295           0 :                                 TALLOC_FREE(smb_dname_full);
    1296           0 :                                 TALLOC_FREE(talloced);
    1297           0 :                                 TALLOC_FREE(direntry_fname);
    1298           0 :                                 continue;
    1299             :                         }
    1300             :                 }
    1301             : 
    1302           0 :                 unlink_flags = 0;
    1303             : 
    1304           0 :                 if (smb_dname_full->st.st_ex_mode & S_IFDIR) {
    1305           0 :                         status = recursive_rmdir(ctx, conn, smb_dname_full);
    1306           0 :                         if (!NT_STATUS_IS_OK(status)) {
    1307           0 :                                 goto err_break;
    1308             :                         }
    1309           0 :                         unlink_flags = AT_REMOVEDIR;
    1310             :                 }
    1311             : 
    1312           0 :                 retval = SMB_VFS_UNLINKAT(conn,
    1313             :                                           dirfsp,
    1314             :                                           direntry_fname,
    1315             :                                           unlink_flags);
    1316           0 :                 if (retval != 0) {
    1317           0 :                         status = map_nt_error_from_unix(errno);
    1318           0 :                         goto err_break;
    1319             :                 }
    1320             : 
    1321             :                 /* Successful iteration. */
    1322           0 :                 do_break = false;
    1323             : 
    1324           0 :         err_break:
    1325           0 :                 TALLOC_FREE(fullname);
    1326           0 :                 TALLOC_FREE(smb_dname_full);
    1327           0 :                 TALLOC_FREE(talloced);
    1328           0 :                 TALLOC_FREE(direntry_fname);
    1329           0 :                 if (do_break) {
    1330           0 :                         break;
    1331             :                 }
    1332             :         }
    1333             : 
    1334             :         /* If we get here, we know NT_STATUS_IS_OK(status) */
    1335           0 :         SMB_ASSERT(NT_STATUS_IS_OK(status));
    1336             : 
    1337             :         /* Retry the rmdir */
    1338           0 :         ret = SMB_VFS_UNLINKAT(conn,
    1339             :                                parent_fname->fsp,
    1340             :                                at_fname,
    1341             :                                AT_REMOVEDIR);
    1342           0 :         if (ret != 0) {
    1343           0 :                 status = map_nt_error_from_unix(errno);
    1344             :         }
    1345             : 
    1346           0 :   err:
    1347             : 
    1348           0 :         TALLOC_FREE(dir_hnd);
    1349           0 :         TALLOC_FREE(parent_fname);
    1350             : 
    1351           0 :         if (!NT_STATUS_IS_OK(status)) {
    1352           0 :                 DBG_NOTICE("couldn't remove directory %s : "
    1353             :                          "%s\n", smb_fname_str_dbg(smb_dname),
    1354             :                          nt_errstr(status));
    1355           0 :                 return status;
    1356             :         }
    1357             : 
    1358           0 :         notify_fname(conn, NOTIFY_ACTION_REMOVED,
    1359             :                      FILE_NOTIFY_CHANGE_DIR_NAME,
    1360           0 :                      smb_dname->base_name);
    1361             : 
    1362           0 :         return status;
    1363             : }
    1364             : 
    1365             : /****************************************************************************
    1366             :  Close a directory opened by an NT SMB call. 
    1367             : ****************************************************************************/
    1368             :   
    1369       10216 : static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
    1370             :                                 enum file_close_type close_type)
    1371             : {
    1372       10216 :         struct share_mode_lock *lck = NULL;
    1373       10216 :         bool delete_dir = False;
    1374       10216 :         NTSTATUS status = NT_STATUS_OK;
    1375       10216 :         NTSTATUS status1 = NT_STATUS_OK;
    1376       10216 :         const struct security_token *del_nt_token = NULL;
    1377       10216 :         const struct security_unix_token *del_token = NULL;
    1378             :         NTSTATUS notify_status;
    1379             : 
    1380       10216 :         SMB_ASSERT(fsp->fsp_flags.is_fsa);
    1381             : 
    1382       10216 :         if (fsp->conn->sconn->using_smb2) {
    1383       10216 :                 notify_status = NT_STATUS_NOTIFY_CLEANUP;
    1384             :         } else {
    1385           0 :                 notify_status = NT_STATUS_OK;
    1386             :         }
    1387             : 
    1388       10216 :         assert_no_pending_aio(fsp, close_type);
    1389             : 
    1390             :         /*
    1391             :          * NT can set delete_on_close of the last open
    1392             :          * reference to a directory also.
    1393             :          */
    1394             : 
    1395       10216 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
    1396       10216 :         if (lck == NULL) {
    1397           0 :                 DEBUG(0, ("close_directory: Could not get share mode lock for "
    1398             :                           "%s\n", fsp_str_dbg(fsp)));
    1399           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1400             :         }
    1401             : 
    1402       10216 :         if (fsp->fsp_flags.initial_delete_on_close) {
    1403             :                 /* Initial delete on close was set - for
    1404             :                  * directories we don't care if anyone else
    1405             :                  * wrote a real delete on close. */
    1406             : 
    1407          10 :                 send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
    1408          10 :                                                fsp->fsp_name->base_name);
    1409          10 :                 set_delete_on_close_lck(fsp, lck,
    1410          10 :                                         fsp->conn->session_info->security_token,
    1411          10 :                                         fsp->conn->session_info->unix_token);
    1412          10 :                 fsp->fsp_flags.delete_on_close = true;
    1413             :         }
    1414             : 
    1415       19534 :         delete_dir = get_delete_on_close_token(
    1416       11024 :                 lck, fsp->name_hash, &del_nt_token, &del_token) &&
    1417         808 :                 !has_other_nonposix_opens(lck, fsp);
    1418             : 
    1419       10216 :         if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
    1420             :                                 delete_dir) {
    1421             :         
    1422             :                 /* Become the user who requested the delete. */
    1423             : 
    1424         808 :                 if (!push_sec_ctx()) {
    1425           0 :                         smb_panic("close_directory: failed to push sec_ctx.\n");
    1426             :                 }
    1427             : 
    1428        3097 :                 set_sec_ctx(del_token->uid,
    1429         808 :                                 del_token->gid,
    1430         808 :                                 del_token->ngroups,
    1431         808 :                                 del_token->groups,
    1432             :                                 del_nt_token);
    1433             : 
    1434         808 :                 if (!del_share_mode(lck, fsp)) {
    1435           0 :                         DEBUG(0, ("close_directory: Could not delete share entry for "
    1436             :                                   "%s\n", fsp_str_dbg(fsp)));
    1437             :                 }
    1438             : 
    1439         808 :                 TALLOC_FREE(lck);
    1440             : 
    1441         808 :                 if ((fsp->conn->fs_capabilities & FILE_NAMED_STREAMS)
    1442         808 :                     && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {
    1443             : 
    1444         808 :                         status = delete_all_streams(fsp->conn, fsp->fsp_name);
    1445         808 :                         if (!NT_STATUS_IS_OK(status)) {
    1446           0 :                                 DEBUG(5, ("delete_all_streams failed: %s\n",
    1447             :                                           nt_errstr(status)));
    1448             :                                 /* unbecome user. */
    1449           0 :                                 pop_sec_ctx();
    1450           0 :                                 return status;
    1451             :                         }
    1452             :                 }
    1453             : 
    1454         808 :                 status = rmdir_internals(talloc_tos(), fsp);
    1455             : 
    1456         808 :                 DEBUG(5,("close_directory: %s. Delete on close was set - "
    1457             :                          "deleting directory returned %s.\n",
    1458             :                          fsp_str_dbg(fsp), nt_errstr(status)));
    1459             : 
    1460             :                 /* unbecome user. */
    1461         808 :                 pop_sec_ctx();
    1462             : 
    1463             :                 /*
    1464             :                  * Ensure we remove any change notify requests that would
    1465             :                  * now fail as the directory has been deleted.
    1466             :                  */
    1467             : 
    1468        1571 :                 if (NT_STATUS_IS_OK(status)) {
    1469         808 :                         notify_status = NT_STATUS_DELETE_PENDING;
    1470             :                 }
    1471             :         } else {
    1472        9408 :                 if (!del_share_mode(lck, fsp)) {
    1473           0 :                         DEBUG(0, ("close_directory: Could not delete share entry for "
    1474             :                                   "%s\n", fsp_str_dbg(fsp)));
    1475             :                 }
    1476             : 
    1477        9408 :                 TALLOC_FREE(lck);
    1478             :         }
    1479             : 
    1480       10216 :         remove_pending_change_notify_requests_by_fid(fsp, notify_status);
    1481             : 
    1482       10216 :         status1 = fd_close(fsp);
    1483             : 
    1484       10216 :         if (!NT_STATUS_IS_OK(status1)) {
    1485           0 :                 DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n",
    1486             :                           fsp_str_dbg(fsp), fsp_get_pathref_fd(fsp), errno,
    1487             :                           strerror(errno)));
    1488             :         }
    1489             : 
    1490       10216 :         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
    1491           0 :                 status = status1;
    1492             :         }
    1493       10216 :         return status;
    1494             : }
    1495             : 
    1496             : /****************************************************************************
    1497             :  Rundown all SMB-related dependencies of a files struct
    1498             : ****************************************************************************/
    1499             :   
    1500       16416 : NTSTATUS close_file_smb(struct smb_request *req,
    1501             :                         struct files_struct *fsp,
    1502             :                         enum file_close_type close_type)
    1503             : {
    1504             :         NTSTATUS status;
    1505             : 
    1506             :         /*
    1507             :          * This fsp can never be an internal dirfsp. They must
    1508             :          * be explicitly closed by TALLOC_FREE of the dir handle.
    1509             :          */
    1510       16416 :         SMB_ASSERT(!fsp->fsp_flags.is_dirfsp);
    1511             : 
    1512             :         /*
    1513             :          * Never call directly on a base fsp
    1514             :          */
    1515       16416 :         SMB_ASSERT(fsp->stream_fsp == NULL);
    1516             : 
    1517       16416 :         if (fsp->fake_file_handle != NULL) {
    1518        3438 :                 status = close_fake_file(req, fsp);
    1519       12978 :         } else if (fsp->print_file != NULL) {
    1520             :                 /* FIXME: return spool errors */
    1521           0 :                 print_spool_end(fsp, close_type);
    1522           0 :                 fd_close(fsp);
    1523           0 :                 status = NT_STATUS_OK;
    1524       12978 :         } else if (!fsp->fsp_flags.is_fsa) {
    1525         912 :                 if (close_type == NORMAL_CLOSE) {
    1526           0 :                         DBG_ERR("unexpected NORMAL_CLOSE for [%s] "
    1527             :                                 "is_fsa[%u] is_pathref[%u] is_directory[%u]\n",
    1528             :                                 fsp_str_dbg(fsp),
    1529             :                                 fsp->fsp_flags.is_fsa,
    1530             :                                 fsp->fsp_flags.is_pathref,
    1531             :                                 fsp->fsp_flags.is_directory);
    1532             :                 }
    1533         912 :                 SMB_ASSERT(close_type != NORMAL_CLOSE);
    1534         912 :                 fd_close(fsp);
    1535         912 :                 status = NT_STATUS_OK;
    1536       12066 :         } else if (fsp->fsp_flags.is_directory) {
    1537       10216 :                 status = close_directory(req, fsp, close_type);
    1538             :         } else {
    1539        1850 :                 status = close_normal_file(req, fsp, close_type);
    1540             :         }
    1541             : 
    1542       16416 :         if (fsp_is_alternate_stream(fsp)) {
    1543             :                 /*
    1544             :                  * fsp was a stream, its base_fsp can't be a stream
    1545             :                  * as well
    1546             :                  */
    1547          64 :                 SMB_ASSERT(!fsp_is_alternate_stream(fsp->base_fsp));
    1548             : 
    1549             :                 /*
    1550             :                  * There's a 1:1 relationship between fsp and a base_fsp
    1551             :                  */
    1552          64 :                 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
    1553             : 
    1554             :                 /*
    1555             :                  * Make base_fsp look standalone now
    1556             :                  */
    1557          64 :                 fsp->base_fsp->stream_fsp = NULL;
    1558             : 
    1559          64 :                 close_file_free(req, &fsp->base_fsp, close_type);
    1560             :         }
    1561             : 
    1562       16416 :         fsp_unbind_smb(req, fsp);
    1563             : 
    1564       16416 :         return status;
    1565             : }
    1566             : 
    1567         358 : NTSTATUS close_file_free(struct smb_request *req,
    1568             :                          struct files_struct **_fsp,
    1569             :                          enum file_close_type close_type)
    1570             : {
    1571         358 :         struct files_struct *fsp = *_fsp;
    1572             :         NTSTATUS status;
    1573             : 
    1574         358 :         status = close_file_smb(req, fsp, close_type);
    1575             : 
    1576         358 :         file_free(req, fsp);
    1577         358 :         *_fsp = NULL;
    1578             : 
    1579         358 :         return status;
    1580             : }
    1581             : 
    1582             : /****************************************************************************
    1583             :  Deal with an (authorized) message to close a file given the share mode
    1584             :  entry.
    1585             : ****************************************************************************/
    1586             : 
    1587           0 : void msg_close_file(struct messaging_context *msg_ctx,
    1588             :                         void *private_data,
    1589             :                         uint32_t msg_type,
    1590             :                         struct server_id server_id,
    1591             :                         DATA_BLOB *data)
    1592             : {
    1593           0 :         files_struct *fsp = NULL;
    1594             :         struct file_id id;
    1595             :         struct share_mode_entry e;
    1596           0 :         struct smbd_server_connection *sconn =
    1597           0 :                 talloc_get_type_abort(private_data,
    1598             :                 struct smbd_server_connection);
    1599             : 
    1600           0 :         message_to_share_mode_entry(&id, &e, (char *)data->data);
    1601             : 
    1602           0 :         if(DEBUGLVL(10)) {
    1603           0 :                 char *sm_str = share_mode_str(NULL, 0, &id, &e);
    1604           0 :                 if (!sm_str) {
    1605           0 :                         smb_panic("talloc failed");
    1606             :                 }
    1607           0 :                 DEBUG(10,("msg_close_file: got request to close share mode "
    1608             :                         "entry %s\n", sm_str));
    1609           0 :                 TALLOC_FREE(sm_str);
    1610             :         }
    1611             : 
    1612           0 :         fsp = file_find_dif(sconn, id, e.share_file_id);
    1613           0 :         if (!fsp) {
    1614           0 :                 DEBUG(10,("msg_close_file: failed to find file.\n"));
    1615           0 :                 return;
    1616             :         }
    1617           0 :         close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1618             : }

Generated by: LCOV version 1.13