LCOV - code coverage report
Current view: top level - source3/smbd - files.c (source / functions) Hit Total Coverage
Test: coverage report for smb2.twrp.listdir_fix f886ca1c Lines: 1014 1191 85.1 %
Date: 2023-11-07 19:11:32 Functions: 61 61 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Files[] structure handling
       4             :    Copyright (C) Andrew Tridgell 1998
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "smbd/smbd.h"
      22             : #include "smbd/globals.h"
      23             : #include "smbd/smbXsrv_open.h"
      24             : #include "libcli/security/security.h"
      25             : #include "util_tdb.h"
      26             : #include "lib/util/bitmap.h"
      27             : #include "lib/util/strv.h"
      28             : #include "lib/util/memcache.h"
      29             : #include "libcli/smb/reparse.h"
      30             : 
      31             : #define FILE_HANDLE_OFFSET 0x1000
      32             : 
      33             : static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
      34             :                                      struct smb_filename **_smb_fname);
      35             : 
      36             : /**
      37             :  * create new fsp to be used for file_new or a durable handle reconnect
      38             :  */
      39     6256669 : NTSTATUS fsp_new(struct connection_struct *conn, TALLOC_CTX *mem_ctx,
      40             :                  files_struct **result)
      41             : {
      42     6256669 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
      43     6256669 :         files_struct *fsp = NULL;
      44     6256669 :         struct smbd_server_connection *sconn = conn->sconn;
      45             : 
      46     6256669 :         fsp = talloc_zero(mem_ctx, struct files_struct);
      47     6256669 :         if (fsp == NULL) {
      48           0 :                 goto fail;
      49             :         }
      50             : 
      51             :         /*
      52             :          * This can't be a child of fsp because the file_handle can be ref'd
      53             :          * when doing a dos/fcb open, which will then share the file_handle
      54             :          * across multiple fsps.
      55             :          */
      56     6256669 :         fsp->fh = fd_handle_create(mem_ctx);
      57     6256669 :         if (fsp->fh == NULL) {
      58           0 :                 goto fail;
      59             :         }
      60             : 
      61     6256669 :         fsp->fsp_flags.use_ofd_locks = !lp_smbd_force_process_locks(SNUM(conn));
      62             : #ifndef HAVE_OFD_LOCKS
      63             :         fsp->fsp_flags.use_ofd_locks = false;
      64             : #endif
      65             : 
      66     6256669 :         fh_set_refcount(fsp->fh, 1);
      67     6256669 :         fsp_set_fd(fsp, -1);
      68             : 
      69     6256669 :         fsp->fnum = FNUM_FIELD_INVALID;
      70     6256669 :         fsp->conn = conn;
      71     6256669 :         fsp->close_write_time = make_omit_timespec();
      72             : 
      73     6256669 :         DLIST_ADD(sconn->files, fsp);
      74     6256669 :         sconn->num_files += 1;
      75             : 
      76     6256669 :         conn->num_files_open++;
      77             : 
      78     6256669 :         DBG_INFO("allocated files structure (%u used)\n",
      79             :                 (unsigned int)sconn->num_files);
      80             : 
      81     6256669 :         *result = fsp;
      82     6256669 :         return NT_STATUS_OK;
      83             : 
      84           0 : fail:
      85           0 :         if (fsp != NULL) {
      86           0 :                 TALLOC_FREE(fsp->fh);
      87             :         }
      88           0 :         TALLOC_FREE(fsp);
      89             : 
      90           0 :         return status;
      91             : }
      92             : 
      93     6107141 : void fsp_set_gen_id(files_struct *fsp)
      94             : {
      95       32280 :         static uint64_t gen_id = 1;
      96             : 
      97             :         /*
      98             :          * A billion of 64-bit increments per second gives us
      99             :          * more than 500 years of runtime without wrap.
     100             :          */
     101     6107141 :         gen_id++;
     102     6107141 :         fh_set_gen_id(fsp->fh, gen_id);
     103     6107141 : }
     104             : 
     105             : /****************************************************************************
     106             :  Find first available file slot.
     107             : ****************************************************************************/
     108             : 
     109      869995 : NTSTATUS fsp_bind_smb(struct files_struct *fsp, struct smb_request *req)
     110             : {
     111      869995 :         struct smbXsrv_open *op = NULL;
     112        3078 :         NTTIME now;
     113        3078 :         NTSTATUS status;
     114             : 
     115      869995 :         if (req == NULL) {
     116      305632 :                 DBG_DEBUG("INTERNAL_OPEN_ONLY, skipping smbXsrv_open\n");
     117      305632 :                 return NT_STATUS_OK;
     118             :         }
     119             : 
     120      564363 :         now = timeval_to_nttime(&fsp->open_time);
     121             : 
     122      564363 :         status = smbXsrv_open_create(req->xconn,
     123      564363 :                                      fsp->conn->session_info,
     124             :                                      now,
     125             :                                      &op);
     126      564363 :         if (!NT_STATUS_IS_OK(status)) {
     127           2 :                 return status;
     128             :         }
     129      564361 :         fsp->op = op;
     130      564361 :         op->compat = fsp;
     131      564361 :         fsp->fnum = op->local_id;
     132             : 
     133      564361 :         fsp->mid = req->mid;
     134      564361 :         req->chain_fsp = fsp;
     135             : 
     136      564361 :         DBG_DEBUG("fsp [%s] mid [%" PRIu64"]\n",
     137             :                 fsp_str_dbg(fsp), fsp->mid);
     138             : 
     139      564361 :         return NT_STATUS_OK;
     140             : }
     141             : 
     142      581700 : NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
     143             :                   files_struct **result)
     144             : {
     145      581700 :         struct smbd_server_connection *sconn = conn->sconn;
     146        2129 :         files_struct *fsp;
     147        2129 :         NTSTATUS status;
     148             : 
     149      581700 :         status = fsp_new(conn, conn, &fsp);
     150      581700 :         if (!NT_STATUS_IS_OK(status)) {
     151           0 :                 return status;
     152             :         }
     153             : 
     154      581700 :         GetTimeOfDay(&fsp->open_time);
     155             : 
     156      581700 :         status = fsp_bind_smb(fsp, req);
     157      581700 :         if (!NT_STATUS_IS_OK(status)) {
     158           2 :                 file_free(NULL, fsp);
     159           2 :                 return status;
     160             :         }
     161             : 
     162      581698 :         fsp_set_gen_id(fsp);
     163             : 
     164             :         /*
     165             :          * Create an smb_filename with "" for the base_name.  There are very
     166             :          * few NULL checks, so make sure it's initialized with something. to
     167             :          * be safe until an audit can be done.
     168             :          */
     169      581698 :         fsp->fsp_name = synthetic_smb_fname(fsp,
     170             :                                             "",
     171             :                                             NULL,
     172             :                                             NULL,
     173             :                                             0,
     174             :                                             0);
     175      581698 :         if (fsp->fsp_name == NULL) {
     176           0 :                 file_free(NULL, fsp);
     177           0 :                 return NT_STATUS_NO_MEMORY;
     178             :         }
     179             : 
     180      581698 :         DBG_INFO("new file %s\n", fsp_fnum_dbg(fsp));
     181             : 
     182             :         /* A new fsp invalidates the positive and
     183             :           negative fsp_fi_cache as the new fsp is pushed
     184             :           at the start of the list and we search from
     185             :           a cache hit to the *end* of the list. */
     186             : 
     187      581698 :         ZERO_STRUCT(sconn->fsp_fi_cache);
     188             : 
     189      581698 :         *result = fsp;
     190      581698 :         return NT_STATUS_OK;
     191             : }
     192             : 
     193      297229 : NTSTATUS create_internal_fsp(connection_struct *conn,
     194             :                              const struct smb_filename *smb_fname,
     195             :                              struct files_struct **_fsp)
     196             : {
     197      297229 :         struct files_struct *fsp = NULL;
     198         957 :         NTSTATUS status;
     199             : 
     200      297229 :         status = file_new(NULL, conn, &fsp);
     201      297229 :         if (!NT_STATUS_IS_OK(status)) {
     202           0 :                 return status;
     203             :         }
     204             : 
     205      297229 :         status = fsp_set_smb_fname(fsp, smb_fname);
     206      297229 :         if (!NT_STATUS_IS_OK(status)) {
     207           0 :                 file_free(NULL, fsp);
     208           0 :                 return status;
     209             :         }
     210             : 
     211      297229 :         *_fsp = fsp;
     212      297229 :         return NT_STATUS_OK;
     213             : }
     214             : 
     215             : /*
     216             :  * Create an internal fsp for an *existing* directory.
     217             :  *
     218             :  * This should only be used by callers in the VFS that need to control the
     219             :  * opening of the directory. Otherwise use open_internal_dirfsp_at().
     220             :  */
     221      288015 : NTSTATUS create_internal_dirfsp(connection_struct *conn,
     222             :                                 const struct smb_filename *smb_dname,
     223             :                                 struct files_struct **_fsp)
     224             : {
     225      288015 :         struct files_struct *fsp = NULL;
     226         957 :         NTSTATUS status;
     227             : 
     228      288015 :         status = create_internal_fsp(conn, smb_dname, &fsp);
     229      288015 :         if (!NT_STATUS_IS_OK(status)) {
     230           0 :                 return status;
     231             :         }
     232             : 
     233      288015 :         fsp->access_mask = FILE_LIST_DIRECTORY;
     234      288015 :         fsp->fsp_flags.is_directory = true;
     235      288015 :         fsp->fsp_flags.is_dirfsp = true;
     236             : 
     237      288015 :         *_fsp = fsp;
     238      288015 :         return NT_STATUS_OK;
     239             : }
     240             : 
     241             : /*
     242             :  * Open an internal fsp for an *existing* directory.
     243             :  */
     244       13119 : NTSTATUS open_internal_dirfsp(connection_struct *conn,
     245             :                               const struct smb_filename *smb_dname,
     246             :                               int _open_flags,
     247             :                               struct files_struct **_fsp)
     248             : {
     249       13119 :         struct vfs_open_how how = { .flags = _open_flags, };
     250       13119 :         struct files_struct *fsp = NULL;
     251          74 :         NTSTATUS status;
     252             : 
     253       13119 :         status = create_internal_dirfsp(conn, smb_dname, &fsp);
     254       13119 :         if (!NT_STATUS_IS_OK(status)) {
     255           0 :                 return status;
     256             :         }
     257             : 
     258             : #ifdef O_DIRECTORY
     259       13119 :         how.flags |= O_DIRECTORY;
     260             : #endif
     261       13119 :         status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, &how);
     262       13119 :         if (!NT_STATUS_IS_OK(status)) {
     263           0 :                 DBG_INFO("Could not open fd for %s (%s)\n",
     264             :                          smb_fname_str_dbg(smb_dname),
     265             :                          nt_errstr(status));
     266           0 :                 file_free(NULL, fsp);
     267           0 :                 return status;
     268             :         }
     269             : 
     270       13119 :         status = vfs_stat_fsp(fsp);
     271       13119 :         if (!NT_STATUS_IS_OK(status)) {
     272           0 :                 file_free(NULL, fsp);
     273           0 :                 return status;
     274             :         }
     275             : 
     276       13119 :         if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
     277           0 :                 DBG_ERR("%s is not a directory!\n",
     278             :                         smb_fname_str_dbg(smb_dname));
     279           0 :                 file_free(NULL, fsp);
     280           0 :                 return NT_STATUS_NOT_A_DIRECTORY;
     281             :         }
     282             : 
     283       13119 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     284             : 
     285       13119 :         *_fsp = fsp;
     286       13119 :         return NT_STATUS_OK;
     287             : }
     288             : 
     289             : /*
     290             :  * Convert a pathref dirfsp into a real fsp. No need to do any cwd
     291             :  * tricks, we just open ".".
     292             :  */
     293      272386 : NTSTATUS openat_internal_dir_from_pathref(
     294             :         struct files_struct *dirfsp,
     295             :         int _open_flags,
     296             :         struct files_struct **_fsp)
     297             : {
     298      272386 :         struct connection_struct *conn = dirfsp->conn;
     299      272386 :         struct smb_filename *smb_dname = dirfsp->fsp_name;
     300      272386 :         struct files_struct *fsp = NULL;
     301      272386 :         char dot[] = ".";
     302      272386 :         struct smb_filename smb_dot = {
     303             :                 .base_name = dot,
     304      272386 :                 .flags = smb_dname->flags,
     305      272386 :                 .twrp = smb_dname->twrp,
     306             :         };
     307      272386 :         struct vfs_open_how how = { .flags = _open_flags, };
     308         883 :         NTSTATUS status;
     309             : 
     310      272386 :         status = create_internal_dirfsp(conn, smb_dname, &fsp);
     311      272386 :         if (!NT_STATUS_IS_OK(status)) {
     312           0 :                 return status;
     313             :         }
     314             : 
     315             :         /*
     316             :          * Pointless for opening ".", but you never know...
     317             :          */
     318      272386 :         how.flags |= O_NOFOLLOW;
     319             : 
     320      272386 :         status = fd_openat(dirfsp, &smb_dot, fsp, &how);
     321      272386 :         if (!NT_STATUS_IS_OK(status)) {
     322           1 :                 DBG_INFO("fd_openat(\"%s\", \".\") failed: %s\n",
     323             :                          fsp_str_dbg(dirfsp),
     324             :                          nt_errstr(status));
     325           1 :                 file_free(NULL, fsp);
     326           1 :                 return status;
     327             :         }
     328             : 
     329      272385 :         fsp->fsp_name->st = smb_dname->st;
     330      272385 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     331      272385 :         *_fsp = fsp;
     332      272385 :         return NT_STATUS_OK;
     333             : }
     334             : 
     335             : /*
     336             :  * The "link" in the name doesn't imply link in the filesystem
     337             :  * sense. It's a object that "links" together an fsp and an smb_fname
     338             :  * and the link allocated as talloc child of an fsp.
     339             :  *
     340             :  * The link is created for fsps that openat_pathref_fsp() returns in
     341             :  * smb_fname->fsp. When this fsp is freed by file_free() by some caller
     342             :  * somewhere, the destructor fsp_smb_fname_link_destructor() on the link object
     343             :  * will use the link to reset the reference in smb_fname->fsp that is about to
     344             :  * go away.
     345             :  *
     346             :  * This prevents smb_fname_internal_fsp_destructor() from seeing dangling fsp
     347             :  * pointers.
     348             :  */
     349             : 
     350             : struct fsp_smb_fname_link {
     351             :         struct fsp_smb_fname_link **smb_fname_link;
     352             :         struct files_struct **smb_fname_fsp;
     353             : };
     354             : 
     355     6055075 : static int fsp_smb_fname_link_destructor(struct fsp_smb_fname_link *link)
     356             : {
     357     6055075 :         if (link->smb_fname_link == NULL) {
     358           0 :                 return 0;
     359             :         }
     360             : 
     361     6055075 :         *link->smb_fname_link = NULL;
     362     6055075 :         *link->smb_fname_fsp = NULL;
     363     6055075 :         return 0;
     364             : }
     365             : 
     366    10250407 : static NTSTATUS fsp_smb_fname_link(struct files_struct *fsp,
     367             :                                    struct fsp_smb_fname_link **smb_fname_link,
     368             :                                    struct files_struct **smb_fname_fsp)
     369             : {
     370    10250407 :         struct fsp_smb_fname_link *link = NULL;
     371             : 
     372    10250407 :         SMB_ASSERT(*smb_fname_link == NULL);
     373    10250407 :         SMB_ASSERT(*smb_fname_fsp == NULL);
     374             : 
     375    10250407 :         link = talloc_zero(fsp, struct fsp_smb_fname_link);
     376    10250407 :         if (link == NULL) {
     377           0 :                 return NT_STATUS_NO_MEMORY;
     378             :         }
     379             : 
     380    10250407 :         link->smb_fname_link = smb_fname_link;
     381    10250407 :         link->smb_fname_fsp = smb_fname_fsp;
     382    10250407 :         *smb_fname_link = link;
     383    10250407 :         *smb_fname_fsp = fsp;
     384             : 
     385    10250407 :         talloc_set_destructor(link, fsp_smb_fname_link_destructor);
     386    10250407 :         return NT_STATUS_OK;
     387             : }
     388             : 
     389             : /*
     390             :  * Free a link, carefully avoiding to trigger the link destructor
     391             :  */
     392     5405763 : static void destroy_fsp_smb_fname_link(struct fsp_smb_fname_link **_link)
     393             : {
     394     5405763 :         struct fsp_smb_fname_link *link = *_link;
     395             : 
     396     5405763 :         if (link == NULL) {
     397     1197916 :                 return;
     398             :         }
     399     4195312 :         talloc_set_destructor(link, NULL);
     400     4195312 :         TALLOC_FREE(link);
     401     4195312 :         *_link = NULL;
     402             : }
     403             : 
     404             : /*
     405             :  * Talloc destructor set on an smb_fname set by openat_pathref_fsp() used to
     406             :  * close the embedded smb_fname->fsp.
     407             :  */
     408     3385673 : static int smb_fname_fsp_destructor(struct smb_filename *smb_fname)
     409             : {
     410     3385673 :         struct files_struct *fsp = smb_fname->fsp;
     411       23274 :         NTSTATUS status;
     412     3385673 :         int saved_errno = errno;
     413             : 
     414     3385673 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
     415             : 
     416     3385673 :         if (fsp == NULL) {
     417        8689 :                 errno = saved_errno;
     418        8689 :                 return 0;
     419             :         }
     420             : 
     421     3376984 :         if (fsp_is_alternate_stream(fsp)) {
     422         775 :                 struct files_struct *tmp_base_fsp = fsp->base_fsp;
     423             : 
     424         775 :                 fsp_set_base_fsp(fsp, NULL);
     425             : 
     426         775 :                 status = fd_close(tmp_base_fsp);
     427         775 :                 if (!NT_STATUS_IS_OK(status)) {
     428           0 :                         DBG_ERR("Closing fd for fsp [%s] failed: %s. "
     429             :                                 "Please check your filesystem!!!\n",
     430             :                                 fsp_str_dbg(fsp), nt_errstr(status));
     431             :                 }
     432         775 :                 file_free(NULL, tmp_base_fsp);
     433             :         }
     434             : 
     435     3376984 :         status = fd_close(fsp);
     436     3376984 :         if (!NT_STATUS_IS_OK(status)) {
     437           0 :                 DBG_ERR("Closing fd for fsp [%s] failed: %s. "
     438             :                         "Please check your filesystem!!!\n",
     439             :                         fsp_str_dbg(fsp), nt_errstr(status));
     440             :         }
     441     3376984 :         file_free(NULL, fsp);
     442     3376984 :         smb_fname->fsp = NULL;
     443             : 
     444     3376984 :         errno = saved_errno;
     445     3376984 :         return 0;
     446             : }
     447             : 
     448     3440219 : static NTSTATUS openat_pathref_fullname(
     449             :         struct connection_struct *conn,
     450             :         const struct files_struct *dirfsp,
     451             :         struct files_struct *basefsp,
     452             :         struct smb_filename **full_fname,
     453             :         struct smb_filename *smb_fname,
     454             :         const struct vfs_open_how *how)
     455             : {
     456     3440219 :         struct files_struct *fsp = NULL;
     457     3440219 :         bool have_dirfsp = (dirfsp != NULL);
     458     3440219 :         bool have_basefsp = (basefsp != NULL);
     459       10701 :         NTSTATUS status;
     460             : 
     461     3440219 :         DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
     462             : 
     463     3440219 :         SMB_ASSERT(smb_fname->fsp == NULL);
     464     3440219 :         SMB_ASSERT(have_dirfsp != have_basefsp);
     465             : 
     466     3440219 :         status = fsp_new(conn, conn, &fsp);
     467     3440219 :         if (!NT_STATUS_IS_OK(status)) {
     468           0 :                 return status;
     469             :         }
     470             : 
     471     3440219 :         GetTimeOfDay(&fsp->open_time);
     472     3440219 :         fsp_set_gen_id(fsp);
     473     3440219 :         ZERO_STRUCT(conn->sconn->fsp_fi_cache);
     474             : 
     475     3440219 :         fsp->fsp_flags.is_pathref = true;
     476             : 
     477     3440219 :         status = fsp_attach_smb_fname(fsp, full_fname);
     478     3440219 :         if (!NT_STATUS_IS_OK(status)) {
     479           0 :                 goto fail;
     480             :         }
     481     3440219 :         fsp_set_base_fsp(fsp, basefsp);
     482             : 
     483     3440219 :         status = fd_openat(dirfsp, smb_fname, fsp, how);
     484     3440219 :         if (!NT_STATUS_IS_OK(status)) {
     485             : 
     486     1508338 :                 smb_fname->st = fsp->fsp_name->st;
     487             : 
     488     1508338 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ||
     489     1506912 :                     NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
     490     1501846 :                     NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK))
     491             :                 {
     492             :                         /*
     493             :                          * streams_xattr return NT_STATUS_NOT_FOUND for
     494             :                          * opens of not yet existing streams.
     495             :                          *
     496             :                          * ELOOP maps to NT_STATUS_OBJECT_PATH_NOT_FOUND
     497             :                          * and this will result from a open request from
     498             :                          * a POSIX client on a symlink.
     499             :                          *
     500             :                          * NT_STATUS_OBJECT_NAME_NOT_FOUND is the simple
     501             :                          * ENOENT case.
     502             :                          *
     503             :                          * NT_STATUS_STOPPED_ON_SYMLINK is returned when trying
     504             :                          * to open a symlink, our callers are not interested in
     505             :                          * this.
     506             :                          */
     507        1499 :                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
     508             :                 }
     509     1508338 :                 goto fail;
     510             :         }
     511             : 
     512             :         /*
     513             :          * fd_openat() has done an FSTAT on the handle
     514             :          * so update the smb_fname stat info with "truth".
     515             :          * from the handle.
     516             :          */
     517     1931881 :         smb_fname->st = fsp->fsp_name->st;
     518             : 
     519     1931881 :         fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
     520             : 
     521     1931881 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     522             : 
     523     1931881 :         status = fsp_smb_fname_link(fsp,
     524             :                                     &smb_fname->fsp_link,
     525             :                                     &smb_fname->fsp);
     526     1931881 :         if (!NT_STATUS_IS_OK(status)) {
     527           0 :                 goto fail;
     528             :         }
     529             : 
     530     1931881 :         DBG_DEBUG("fsp [%s]: OK\n", fsp_str_dbg(fsp));
     531             : 
     532     1931881 :         talloc_set_destructor(smb_fname, smb_fname_fsp_destructor);
     533     1931881 :         return NT_STATUS_OK;
     534             : 
     535     1508338 : fail:
     536     1508338 :         DBG_DEBUG("Opening pathref for [%s] failed: %s\n",
     537             :                   smb_fname_str_dbg(smb_fname),
     538             :                   nt_errstr(status));
     539             : 
     540     1508338 :         fsp_set_base_fsp(fsp, NULL);
     541     1508338 :         fd_close(fsp);
     542     1508338 :         file_free(NULL, fsp);
     543     1508338 :         return status;
     544             : }
     545             : 
     546             : /*
     547             :  * Open an internal O_PATH based fsp for smb_fname. If O_PATH is not
     548             :  * available, open O_RDONLY as root. Both is done in fd_open() ->
     549             :  * non_widelink_open(), triggered by setting fsp->fsp_flags.is_pathref to
     550             :  * true.
     551             :  */
     552     3432463 : NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
     553             :                             struct smb_filename *smb_fname)
     554             : {
     555     3432463 :         connection_struct *conn = dirfsp->conn;
     556     3432463 :         struct smb_filename *full_fname = NULL;
     557     3432463 :         struct smb_filename *base_fname = NULL;
     558     3432463 :         struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
     559       10719 :         NTSTATUS status;
     560             : 
     561     3432463 :         DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
     562             : 
     563     3432463 :         if (smb_fname->fsp != NULL) {
     564             :                 /* We already have one for this name. */
     565         450 :                 DBG_DEBUG("smb_fname [%s] already has a pathref fsp.\n",
     566             :                         smb_fname_str_dbg(smb_fname));
     567         450 :                 return NT_STATUS_OK;
     568             :         }
     569             : 
     570     3432013 :         if (is_named_stream(smb_fname) &&
     571        1977 :             ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
     572           0 :                 DBG_DEBUG("stream open [%s] on non-stream share\n",
     573             :                           smb_fname_str_dbg(smb_fname));
     574           0 :                 return NT_STATUS_OBJECT_NAME_INVALID;
     575             :         }
     576             : 
     577     3432013 :         if (!is_named_stream(smb_fname)) {
     578             :                 /*
     579             :                  * openat_pathref_fullname() will make "full_fname" a
     580             :                  * talloc child of the smb_fname->fsp. Don't use
     581             :                  * talloc_tos() to allocate it to avoid making the
     582             :                  * talloc stackframe pool long-lived.
     583             :                  */
     584     3430036 :                 full_fname = full_path_from_dirfsp_atname(
     585             :                         conn,
     586             :                         dirfsp,
     587             :                         smb_fname);
     588     3430036 :                 if (full_fname == NULL) {
     589           0 :                         status = NT_STATUS_NO_MEMORY;
     590           0 :                         goto fail;
     591             :                 }
     592     3430036 :                 status = openat_pathref_fullname(
     593             :                         conn, dirfsp, NULL, &full_fname, smb_fname, &how);
     594     3430036 :                 TALLOC_FREE(full_fname);
     595     3430036 :                 return status;
     596             :         }
     597             : 
     598             :         /*
     599             :          * stream open
     600             :          */
     601        1977 :         base_fname = cp_smb_filename_nostream(conn, smb_fname);
     602        1977 :         if (base_fname == NULL) {
     603           0 :                 return NT_STATUS_NO_MEMORY;
     604             :         }
     605             : 
     606        1977 :         full_fname = full_path_from_dirfsp_atname(
     607             :                 conn,   /* no talloc_tos(), see comment above */
     608             :                 dirfsp,
     609             :                 base_fname);
     610        1977 :         if (full_fname == NULL) {
     611           0 :                 status = NT_STATUS_NO_MEMORY;
     612           0 :                 goto fail;
     613             :         }
     614             : 
     615        1977 :         status = openat_pathref_fullname(
     616             :                 conn, dirfsp, NULL, &full_fname, base_fname, &how);
     617        1977 :         TALLOC_FREE(full_fname);
     618        1977 :         if (!NT_STATUS_IS_OK(status)) {
     619           0 :                 DBG_DEBUG("openat_pathref_fullname() failed: %s\n",
     620             :                           nt_errstr(status));
     621           0 :                 goto fail;
     622             :         }
     623             : 
     624        1977 :         status = open_stream_pathref_fsp(&base_fname->fsp, smb_fname);
     625        1977 :         if (!NT_STATUS_IS_OK(status)) {
     626         282 :                 DBG_DEBUG("open_stream_pathref_fsp failed: %s\n",
     627             :                           nt_errstr(status));
     628         282 :                 goto fail;
     629             :         }
     630             : 
     631        1695 :         smb_fname_fsp_unlink(base_fname);
     632        1977 : fail:
     633        1977 :         TALLOC_FREE(base_fname);
     634        1977 :         return status;
     635             : }
     636             : 
     637             : /*
     638             :  * Open a stream given an already opened base_fsp. Avoid
     639             :  * non_widelink_open: This is only valid for the case where we have a
     640             :  * valid non-cwd_fsp dirfsp that we can pass to SMB_VFS_OPENAT()
     641             :  */
     642        8206 : NTSTATUS open_stream_pathref_fsp(
     643             :         struct files_struct **_base_fsp,
     644             :         struct smb_filename *smb_fname)
     645             : {
     646        8206 :         struct files_struct *base_fsp = *_base_fsp;
     647        8206 :         connection_struct *conn = base_fsp->conn;
     648        8206 :         struct smb_filename *base_fname = base_fsp->fsp_name;
     649        8206 :         struct smb_filename *full_fname = NULL;
     650        8206 :         struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
     651           4 :         NTSTATUS status;
     652             : 
     653        8206 :         SMB_ASSERT(smb_fname->fsp == NULL);
     654        8206 :         SMB_ASSERT(is_named_stream(smb_fname));
     655             : 
     656       16412 :         full_fname = synthetic_smb_fname(
     657             :                 conn, /* no talloc_tos(), this will be long-lived */
     658        8206 :                 base_fname->base_name,
     659        8206 :                 smb_fname->stream_name,
     660        8206 :                 &smb_fname->st,
     661             :                 smb_fname->twrp,
     662             :                 smb_fname->flags);
     663        8206 :         if (full_fname == NULL) {
     664           0 :                 return NT_STATUS_NO_MEMORY;
     665             :         }
     666             : 
     667        8206 :         status = openat_pathref_fullname(
     668             :                 conn, NULL, base_fsp, &full_fname, smb_fname, &how);
     669        8206 :         TALLOC_FREE(full_fname);
     670        8206 :         return status;
     671             : }
     672             : 
     673     1464938 : static char *path_to_strv(TALLOC_CTX *mem_ctx, const char *path)
     674             : {
     675     1464938 :         char *result = talloc_strdup(mem_ctx, path);
     676             : 
     677     1464938 :         if (result == NULL) {
     678           0 :                 return NULL;
     679             :         }
     680     1464938 :         string_replace(result, '/', '\0');
     681     1464938 :         return result;
     682             : }
     683             : 
     684       76245 : NTSTATUS readlink_talloc(
     685             :         TALLOC_CTX *mem_ctx,
     686             :         struct files_struct *dirfsp,
     687             :         struct smb_filename *smb_relname,
     688             :         char **_substitute)
     689             : {
     690       76245 :         struct smb_filename null_fname = {
     691             :                 .base_name = discard_const_p(char, ""),
     692             :         };
     693           0 :         char buf[PATH_MAX];
     694           0 :         ssize_t ret;
     695           0 :         char *substitute;
     696           0 :         NTSTATUS status;
     697             : 
     698       76245 :         if (smb_relname == NULL) {
     699             :                 /*
     700             :                  * We have a Linux O_PATH handle in dirfsp and want to
     701             :                  * read its value, essentially a freadlink
     702             :                  */
     703       40092 :                 smb_relname = &null_fname;
     704             :         }
     705             : 
     706       76245 :         ret = SMB_VFS_READLINKAT(
     707             :                 dirfsp->conn, dirfsp, smb_relname, buf, sizeof(buf));
     708       76245 :         if (ret < 0) {
     709          24 :                 status = map_nt_error_from_unix(errno);
     710          24 :                 DBG_DEBUG("SMB_VFS_READLINKAT() failed: %s\n",
     711             :                           strerror(errno));
     712          24 :                 return status;
     713             :         }
     714             : 
     715       76221 :         if ((size_t)ret == sizeof(buf)) {
     716             :                 /*
     717             :                  * Do we need symlink targets longer than PATH_MAX?
     718             :                  */
     719           0 :                 DBG_DEBUG("Got full %zu bytes from readlink, too long\n",
     720             :                           sizeof(buf));
     721           0 :                 return NT_STATUS_BUFFER_OVERFLOW;
     722             :         }
     723             : 
     724       76221 :         substitute = talloc_strndup(mem_ctx, buf, ret);
     725       76221 :         if (substitute == NULL) {
     726           0 :                 DBG_DEBUG("talloc_strndup() failed\n");
     727           0 :                 return NT_STATUS_NO_MEMORY;
     728             :         }
     729             : 
     730       76221 :         *_substitute = substitute;
     731       76221 :         return NT_STATUS_OK;
     732             : }
     733             : 
     734       73884 : NTSTATUS read_symlink_reparse(
     735             :         TALLOC_CTX *mem_ctx,
     736             :         struct files_struct *dirfsp,
     737             :         struct smb_filename *smb_relname,
     738             :         struct symlink_reparse_struct **_symlink)
     739             : {
     740       73884 :         struct symlink_reparse_struct *symlink = NULL;
     741           0 :         NTSTATUS status;
     742             : 
     743       73884 :         symlink = talloc_zero(mem_ctx, struct symlink_reparse_struct);
     744       73884 :         if (symlink == NULL) {
     745           0 :                 goto nomem;
     746             :         }
     747             : 
     748       73884 :         status = readlink_talloc(
     749             :                 symlink, dirfsp, smb_relname, &symlink->substitute_name);
     750       73884 :         if (!NT_STATUS_IS_OK(status)) {
     751          24 :                 DBG_DEBUG("readlink_talloc failed: %s\n", nt_errstr(status));
     752          24 :                 goto fail;
     753             :         }
     754             : 
     755       73860 :         if (symlink->substitute_name[0] == '/') {
     756       20692 :                 char *subdir_path = NULL;
     757       20692 :                 char *abs_target_canon = NULL;
     758       20692 :                 const char *relative = NULL;
     759           0 :                 bool in_share;
     760             : 
     761       20692 :                 subdir_path = talloc_asprintf(talloc_tos(),
     762             :                                               "%s/%s",
     763       20692 :                                               dirfsp->conn->connectpath,
     764       20692 :                                               dirfsp->fsp_name->base_name);
     765       20692 :                 if (subdir_path == NULL) {
     766           0 :                         goto nomem;
     767             :                 }
     768             : 
     769           0 :                 abs_target_canon =
     770       20692 :                         canonicalize_absolute_path(talloc_tos(),
     771       20692 :                                                    symlink->substitute_name);
     772       20692 :                 if (abs_target_canon == NULL) {
     773           0 :                         goto nomem;
     774             :                 }
     775             : 
     776       20692 :                 in_share = subdir_of(subdir_path,
     777             :                                      strlen(subdir_path),
     778             :                                      abs_target_canon,
     779             :                                      &relative);
     780       20692 :                 if (in_share) {
     781        7814 :                         TALLOC_FREE(symlink->substitute_name);
     782        7814 :                         symlink->substitute_name =
     783        7814 :                                 talloc_strdup(symlink, relative);
     784        7814 :                         if (symlink->substitute_name == NULL) {
     785           0 :                                 goto nomem;
     786             :                         }
     787             :                 }
     788             :         }
     789             : 
     790       73860 :         if (!IS_DIRECTORY_SEP(symlink->substitute_name[0])) {
     791       60982 :                 symlink->flags |= SYMLINK_FLAG_RELATIVE;
     792             :         }
     793             : 
     794       73860 :         *_symlink = symlink;
     795       73860 :         return NT_STATUS_OK;
     796           0 : nomem:
     797           0 :         status = NT_STATUS_NO_MEMORY;
     798          24 : fail:
     799          24 :         TALLOC_FREE(symlink);
     800          24 :         return status;
     801             : }
     802             : 
     803     1574885 : static bool full_path_extend(char **dir, const char *atname)
     804             : {
     805     1574885 :         talloc_asprintf_addbuf(dir,
     806             :                                "%s%s",
     807     1574885 :                                (*dir)[0] == '\0' ? "" : "/",
     808             :                                atname);
     809     1574885 :         return (*dir) != NULL;
     810             : }
     811             : 
     812       73884 : NTSTATUS create_open_symlink_err(TALLOC_CTX *mem_ctx,
     813             :                                  files_struct *dirfsp,
     814             :                                  struct smb_filename *smb_relname,
     815             :                                  struct open_symlink_err **_err)
     816             : {
     817       73884 :         struct open_symlink_err *err = NULL;
     818           0 :         NTSTATUS status;
     819             : 
     820       73884 :         err = talloc_zero(mem_ctx, struct open_symlink_err);
     821       73884 :         if (err == NULL) {
     822           0 :                 return NT_STATUS_NO_MEMORY;
     823             :         }
     824             : 
     825       73884 :         status = read_symlink_reparse(err, dirfsp, smb_relname, &err->reparse);
     826       73884 :         if (!NT_STATUS_IS_OK(status)) {
     827          24 :                 TALLOC_FREE(err);
     828          24 :                 return status;
     829             :         }
     830             : 
     831       73860 :         *_err = err;
     832       73860 :         return NT_STATUS_OK;
     833             : }
     834             : 
     835             : /*
     836             :  * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
     837             :  * the stat cache for the last component to be looked up. Cache
     838             :  * contents is the correctly capitalized translation of the parameter
     839             :  * "name" as it exists on disk. This is indexed by inode of the dirfsp
     840             :  * and name, and contrary to stat_cahce_lookup() it does not
     841             :  * vfs_stat() the last component. This will be taken care of by an
     842             :  * attempt to do a openat_pathref_fsp().
     843             :  */
     844      268652 : static bool get_real_filename_cache_key(TALLOC_CTX *mem_ctx,
     845             :                                         struct files_struct *dirfsp,
     846             :                                         const char *name,
     847             :                                         DATA_BLOB *_key)
     848             : {
     849      268652 :         struct file_id fid = vfs_file_id_from_sbuf(dirfsp->conn,
     850      268652 :                                                    &dirfsp->fsp_name->st);
     851      268652 :         char *upper = NULL;
     852      268652 :         uint8_t *key = NULL;
     853         885 :         size_t namelen, keylen;
     854             : 
     855      268652 :         upper = talloc_strdup_upper(mem_ctx, name);
     856      268652 :         if (upper == NULL) {
     857           0 :                 return false;
     858             :         }
     859      268652 :         namelen = talloc_get_size(upper);
     860             : 
     861      268652 :         keylen = namelen + sizeof(fid);
     862      268652 :         if (keylen < sizeof(fid)) {
     863           0 :                 TALLOC_FREE(upper);
     864           0 :                 return false;
     865             :         }
     866             : 
     867      268652 :         key = talloc_size(mem_ctx, keylen);
     868      268652 :         if (key == NULL) {
     869           0 :                 TALLOC_FREE(upper);
     870           0 :                 return false;
     871             :         }
     872             : 
     873      268652 :         memcpy(key, &fid, sizeof(fid));
     874      268652 :         memcpy(key + sizeof(fid), upper, namelen);
     875      268652 :         TALLOC_FREE(upper);
     876             : 
     877      268652 :         *_key = (DATA_BLOB){
     878             :                 .data = key,
     879             :                 .length = keylen,
     880             :         };
     881      268652 :         return true;
     882             : }
     883             : 
     884     1634602 : static int smb_vfs_openat_ci(TALLOC_CTX *mem_ctx,
     885             :                              bool case_sensitive,
     886             :                              struct connection_struct *conn,
     887             :                              struct files_struct *dirfsp,
     888             :                              struct smb_filename *smb_fname_rel,
     889             :                              files_struct *fsp,
     890             :                              const struct vfs_open_how *how)
     891             : {
     892     1634602 :         char *orig_base_name = smb_fname_rel->base_name;
     893     1634602 :         DATA_BLOB cache_key = {
     894             :                 .data = NULL,
     895             :         };
     896     1634602 :         DATA_BLOB cache_value = {
     897             :                 .data = NULL,
     898             :         };
     899       19454 :         NTSTATUS status;
     900       19454 :         int fd;
     901       19454 :         bool ok;
     902             : 
     903     1634602 :         fd = SMB_VFS_OPENAT(conn, dirfsp, smb_fname_rel, fsp, how);
     904     1634602 :         if ((fd >= 0) || case_sensitive) {
     905     1284226 :                 return fd;
     906             :         }
     907      331807 :         if (errno != ENOENT) {
     908       63155 :                 return -1;
     909             :         }
     910             : 
     911      268652 :         if (!lp_stat_cache()) {
     912           0 :                 goto lookup;
     913             :         }
     914             : 
     915      268652 :         ok = get_real_filename_cache_key(mem_ctx,
     916             :                                          dirfsp,
     917             :                                          orig_base_name,
     918             :                                          &cache_key);
     919      268652 :         if (!ok) {
     920             :                 /*
     921             :                  * probably ENOMEM, just bail
     922             :                  */
     923           0 :                 errno = ENOMEM;
     924           0 :                 return -1;
     925             :         }
     926             : 
     927      268652 :         DO_PROFILE_INC(statcache_lookups);
     928             : 
     929      268652 :         ok = memcache_lookup(NULL,
     930             :                              GETREALFILENAME_CACHE,
     931             :                              cache_key,
     932             :                              &cache_value);
     933      268652 :         if (!ok) {
     934      267572 :                 DO_PROFILE_INC(statcache_misses);
     935      267572 :                 goto lookup;
     936             :         }
     937        1080 :         DO_PROFILE_INC(statcache_hits);
     938             : 
     939        2160 :         smb_fname_rel->base_name = talloc_strndup(mem_ctx,
     940        1080 :                                                   (char *)cache_value.data,
     941             :                                                   cache_value.length);
     942        1080 :         if (smb_fname_rel->base_name == NULL) {
     943           0 :                 TALLOC_FREE(cache_key.data);
     944           0 :                 smb_fname_rel->base_name = orig_base_name;
     945           0 :                 errno = ENOMEM;
     946           0 :                 return -1;
     947             :         }
     948             : 
     949        1080 :         if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
     950           0 :                 DBG_DEBUG("veto files rejecting last component %s\n",
     951             :                           smb_fname_str_dbg(smb_fname_rel));
     952           0 :                 TALLOC_FREE(cache_key.data);
     953           0 :                 smb_fname_rel->base_name = orig_base_name;
     954           0 :                 errno = EPERM;
     955           0 :                 return -1;
     956             :         }
     957             : 
     958        1080 :         fd = SMB_VFS_OPENAT(conn, dirfsp, smb_fname_rel, fsp, how);
     959        1080 :         if (fd >= 0) {
     960        1012 :                 TALLOC_FREE(cache_key.data);
     961        1012 :                 return fd;
     962             :         }
     963             : 
     964          68 :         memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
     965             : 
     966             :         /*
     967             :          * For the "new filename" case we need to preserve the
     968             :          * capitalization the client sent us, see
     969             :          * https://bugzilla.samba.org/show_bug.cgi?id=15481
     970             :          */
     971          68 :         TALLOC_FREE(smb_fname_rel->base_name);
     972          68 :         smb_fname_rel->base_name = orig_base_name;
     973             : 
     974      267640 : lookup:
     975             : 
     976      267640 :         status = get_real_filename_at(dirfsp,
     977             :                                       orig_base_name,
     978             :                                       mem_ctx,
     979             :                                       &smb_fname_rel->base_name);
     980      267640 :         if (!NT_STATUS_IS_OK(status)) {
     981      266881 :                 DBG_DEBUG("get_real_filename_at() failed: %s\n",
     982             :                           nt_errstr(status));
     983      266881 :                 errno = ENOENT;
     984      266881 :                 return -1;
     985             :         }
     986             : 
     987         759 :         if (IS_VETO_PATH(conn, smb_fname_rel->base_name)) {
     988          24 :                 DBG_DEBUG("found veto files path component "
     989             :                           "%s => %s\n",
     990             :                           orig_base_name,
     991             :                           smb_fname_rel->base_name);
     992          24 :                 TALLOC_FREE(smb_fname_rel->base_name);
     993          24 :                 smb_fname_rel->base_name = orig_base_name;
     994          24 :                 errno = ENOENT;
     995          24 :                 return -1;
     996             :         }
     997             : 
     998         735 :         fd = SMB_VFS_OPENAT(conn, dirfsp, smb_fname_rel, fsp, how);
     999             : 
    1000         735 :         if ((fd >= 0) && (cache_key.data != NULL)) {
    1001         651 :                 DATA_BLOB value = {
    1002         651 :                         .data = (uint8_t *)smb_fname_rel->base_name,
    1003         651 :                         .length = strlen(smb_fname_rel->base_name) + 1,
    1004             :                 };
    1005             : 
    1006         651 :                 memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
    1007         651 :                 TALLOC_FREE(cache_key.data);
    1008             :         }
    1009             : 
    1010         731 :         return fd;
    1011             : }
    1012             : 
    1013     1464938 : NTSTATUS openat_pathref_fsp_nosymlink(TALLOC_CTX *mem_ctx,
    1014             :                                       struct connection_struct *conn,
    1015             :                                       struct files_struct *in_dirfsp,
    1016             :                                       const char *path_in,
    1017             :                                       NTTIME twrp,
    1018             :                                       bool posix,
    1019             :                                       struct smb_filename **_smb_fname,
    1020             :                                       struct open_symlink_err **_symlink_err)
    1021             : {
    1022     1464938 :         struct files_struct *dirfsp = in_dirfsp;
    1023     2929876 :         struct smb_filename full_fname = {
    1024             :                 .base_name = NULL,
    1025             :                 .twrp = twrp,
    1026     1464938 :                 .flags = posix ? SMB_FILENAME_POSIX_PATH : 0,
    1027             :         };
    1028     1464938 :         struct smb_filename rel_fname = {
    1029             :                 .base_name = NULL,
    1030             :                 .twrp = twrp,
    1031     1455892 :                 .flags = full_fname.flags,
    1032             :         };
    1033     1464938 :         struct smb_filename *result = NULL;
    1034     1464938 :         struct open_symlink_err *symlink_err = NULL;
    1035     1464938 :         struct files_struct *fsp = NULL;
    1036     1464938 :         char *path = NULL, *next = NULL;
    1037        9046 :         bool ok, is_toplevel;
    1038        9046 :         int fd;
    1039        9046 :         NTSTATUS status;
    1040     1464938 :         struct vfs_open_how how = {
    1041             :                 .flags = O_NOFOLLOW | O_NONBLOCK,
    1042             :                 .mode = 0,
    1043             :         };
    1044             : 
    1045     1464938 :         DBG_DEBUG("path_in=%s\n", path_in);
    1046             : 
    1047     1464938 :         status = fsp_new(conn, conn, &fsp);
    1048     1464938 :         if (!NT_STATUS_IS_OK(status)) {
    1049           0 :                 DBG_DEBUG("fsp_new() failed: %s\n", nt_errstr(status));
    1050           0 :                 goto fail;
    1051             :         }
    1052             : 
    1053     1464938 :         GetTimeOfDay(&fsp->open_time);
    1054     1464938 :         fsp_set_gen_id(fsp);
    1055     1464938 :         ZERO_STRUCT(conn->sconn->fsp_fi_cache);
    1056             : 
    1057     1464938 :         fsp->fsp_name = &full_fname;
    1058             : 
    1059             : #ifdef O_PATH
    1060             :         /*
    1061             :          * Add O_PATH manually, doing this by setting
    1062             :          * fsp->fsp_flags.is_pathref will make us become_root() in the
    1063             :          * non-O_PATH case, which would cause a security problem.
    1064             :          */
    1065     1024198 :         how.flags |= O_PATH;
    1066             : #else
    1067             : #ifdef O_SEARCH
    1068             :         /*
    1069             :          * O_SEARCH just checks for the "x" bit. We are traversing
    1070             :          * directories, so we don't need the implicit O_RDONLY ("r"
    1071             :          * permissions) but only the "x"-permissions requested by
    1072             :          * O_SEARCH. We need either O_PATH or O_SEARCH to correctly
    1073             :          * function, without either we will incorrectly require also
    1074             :          * the "r" bit when traversing the directory hierarchy.
    1075             :          */
    1076             :         how.flags |= O_SEARCH;
    1077             : #endif
    1078             : #endif
    1079             : 
    1080     1464938 :         is_toplevel = (dirfsp == dirfsp->conn->cwd_fsp);
    1081     1464938 :         is_toplevel |= ISDOT(dirfsp->fsp_name->base_name);
    1082             : 
    1083     1473984 :         full_fname.base_name =
    1084     2324132 :                 talloc_strdup(talloc_tos(),
    1085      859144 :                               is_toplevel ? "" : dirfsp->fsp_name->base_name);
    1086     1464938 :         if (full_fname.base_name == NULL) {
    1087           0 :                 DBG_DEBUG("talloc_strdup() failed\n");
    1088           0 :                 goto nomem;
    1089             :         }
    1090             : 
    1091             :         /*
    1092             :          * First split the path into individual components.
    1093             :          */
    1094     1464938 :         path = path_to_strv(talloc_tos(), path_in);
    1095     1464938 :         if (path == NULL) {
    1096           0 :                 DBG_DEBUG("path_to_strv() failed\n");
    1097           0 :                 goto nomem;
    1098             :         }
    1099             : 
    1100             :         /*
    1101             :          * First we loop over all components
    1102             :          * in order to verify, there's no '.' or '..'
    1103             :          */
    1104     1464938 :         rel_fname.base_name = path;
    1105     3972756 :         while (rel_fname.base_name != NULL) {
    1106             : 
    1107     2507968 :                 next = strv_next(path, rel_fname.base_name);
    1108             : 
    1109             :                 /*
    1110             :                  * Path sanitizing further up has cleaned or rejected
    1111             :                  * empty path components. Assert this here.
    1112             :                  */
    1113     2507968 :                 SMB_ASSERT(rel_fname.base_name[0] != '\0');
    1114             : 
    1115     2507968 :                 if (ISDOT(rel_fname.base_name) ||
    1116     2498786 :                     ISDOTDOT(rel_fname.base_name)) {
    1117         132 :                         DBG_DEBUG("%s contains a dot\n", path_in);
    1118         132 :                         status = NT_STATUS_OBJECT_NAME_INVALID;
    1119         132 :                         goto fail;
    1120             :                 }
    1121             : 
    1122             :                 /* Check veto files. */
    1123     2507836 :                 if (IS_VETO_PATH(conn, rel_fname.base_name)) {
    1124          18 :                         DBG_DEBUG("%s contains veto files path component %s\n",
    1125             :                                   path_in, rel_fname.base_name);
    1126          18 :                         status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
    1127          18 :                         goto fail;
    1128             :                 }
    1129             : 
    1130     2507818 :                 rel_fname.base_name = next;
    1131             :         }
    1132             : 
    1133     1464788 :         if (conn->open_how_resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
    1134             : 
    1135             :                 /*
    1136             :                  * Try a direct openat2 with RESOLVE_NO_SYMLINKS to
    1137             :                  * avoid the openat/close loop further down.
    1138             :                  */
    1139             : 
    1140      734463 :                 rel_fname.base_name = discard_const_p(char, path_in);
    1141      734463 :                 how.resolve = VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
    1142             : 
    1143      734463 :                 fd = SMB_VFS_OPENAT(conn, dirfsp, &rel_fname, fsp, &how);
    1144      734463 :                 if (fd >= 0) {
    1145      620981 :                         fsp_set_fd(fsp, fd);
    1146      620981 :                         ok = full_path_extend(&full_fname.base_name,
    1147      620981 :                                               rel_fname.base_name);
    1148      620981 :                         if (!ok) {
    1149           0 :                                 goto nomem;
    1150             :                         }
    1151      620981 :                         goto done;
    1152             :                 }
    1153             : 
    1154      113482 :                 status = map_nt_error_from_unix(errno);
    1155      113482 :                 DBG_DEBUG("SMB_VFS_OPENAT(%s, %s, RESOLVE_NO_SYMLINKS) "
    1156             :                           "returned %d %s => %s\n",
    1157             :                           smb_fname_str_dbg(dirfsp->fsp_name), path_in,
    1158             :                           errno, strerror(errno), nt_errstr(status));
    1159      113482 :                 SMB_ASSERT(fd == -1);
    1160      113482 :                 switch (errno) {
    1161       95189 :                 case ENOSYS:
    1162             :                         /*
    1163             :                          * We got ENOSYS, so fallback to the old code
    1164             :                          * if the kernel doesn't support openat2() yet.
    1165             :                          */
    1166       95189 :                         break;
    1167             : 
    1168       16905 :                 case ELOOP:
    1169             :                 case ENOTDIR:
    1170             :                         /*
    1171             :                          * For ELOOP we also fallback in order to
    1172             :                          * return the correct information with
    1173             :                          * NT_STATUS_STOPPED_ON_SYMLINK.
    1174             :                          *
    1175             :                          * O_NOFOLLOW|O_DIRECTORY results in
    1176             :                          * ENOTDIR instead of ELOOP for the final
    1177             :                          * component.
    1178             :                          */
    1179       16905 :                         break;
    1180             : 
    1181        1315 :                 case ENOENT:
    1182             :                         /*
    1183             :                          * If we got ENOENT, the filesystem could
    1184             :                          * be case sensitive. For now we only do
    1185             :                          * the get_real_filename_at() dance in
    1186             :                          * the fallback loop below.
    1187             :                          */
    1188        1315 :                         break;
    1189             : 
    1190           3 :                 default:
    1191           3 :                         goto fail;
    1192             :                 }
    1193             : 
    1194             :                 /*
    1195             :                  * Just fallback to the openat loop
    1196             :                  */
    1197      113479 :                 how.resolve = 0;
    1198             :         }
    1199             : 
    1200             :         /*
    1201             :          * Now we loop over all components
    1202             :          * opening each one and using it
    1203             :          * as dirfd for the next one.
    1204             :          *
    1205             :          * It means we can detect symlinks
    1206             :          * within the path.
    1207             :          */
    1208      843804 :         rel_fname.base_name = path;
    1209     1014454 : next:
    1210     1014454 :         next = strv_next(path, rel_fname.base_name);
    1211             : 
    1212     1014454 :         fd = smb_vfs_openat_ci(talloc_tos(),
    1213     1014454 :                                posix || conn->case_sensitive,
    1214             :                                conn,
    1215             :                                dirfsp,
    1216             :                                &rel_fname,
    1217             :                                fsp,
    1218             :                                &how);
    1219             : 
    1220             : #ifndef O_PATH
    1221      511403 :         if ((fd == -1) && (errno == ELOOP)) {
    1222             :                 int ret;
    1223             : 
    1224             :                 /*
    1225             :                  * openat() hit a symlink. With O_PATH we open the
    1226             :                  * symlink and get ENOTDIR in the next round, see
    1227             :                  * below.
    1228             :                  */
    1229             : 
    1230       25799 :                 status = create_open_symlink_err(mem_ctx,
    1231             :                                                  dirfsp,
    1232             :                                                  &rel_fname,
    1233             :                                                  &symlink_err);
    1234       25799 :                 if (!NT_STATUS_IS_OK(status)) {
    1235           0 :                         DBG_DEBUG("create_open_symlink_err failed: %s\n",
    1236             :                                   nt_errstr(status));
    1237           0 :                         goto fail;
    1238             :                 }
    1239             : 
    1240       25799 :                 if (next != NULL) {
    1241       22181 :                         size_t parsed = next - path;
    1242       22181 :                         size_t len = talloc_get_size(path);
    1243       22181 :                         symlink_err->unparsed = len - parsed;
    1244             :                 }
    1245             : 
    1246             :                 /*
    1247             :                  * We know rel_fname is a symlink, now fill in the
    1248             :                  * rest of the metadata for our callers.
    1249             :                  */
    1250             : 
    1251       25799 :                 ret = SMB_VFS_FSTATAT(conn,
    1252             :                                       dirfsp,
    1253             :                                       &rel_fname,
    1254             :                                       &symlink_err->st,
    1255             :                                       AT_SYMLINK_NOFOLLOW);
    1256       25799 :                 if (ret == -1) {
    1257           0 :                         status = map_nt_error_from_unix(errno);
    1258           0 :                         DBG_DEBUG("SMB_VFS_FSTATAT(%s/%s) failed: %s\n",
    1259             :                                   fsp_str_dbg(dirfsp),
    1260             :                                   rel_fname.base_name,
    1261             :                                   strerror(errno));
    1262           0 :                         TALLOC_FREE(symlink_err);
    1263           0 :                         goto fail;
    1264             :                 }
    1265             : 
    1266       25799 :                 if (!S_ISLNK(symlink_err->st.st_ex_mode)) {
    1267             :                         /*
    1268             :                          * Hit a race: readlink_talloc() worked before
    1269             :                          * the fstatat(), but rel_fname changed to
    1270             :                          * something that's not a symlink.
    1271             :                          */
    1272           0 :                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1273           0 :                         TALLOC_FREE(symlink_err);
    1274           0 :                         goto fail;
    1275             :                 }
    1276             : 
    1277       25799 :                 status = NT_STATUS_STOPPED_ON_SYMLINK;
    1278       25799 :                 goto fail;
    1279             :         }
    1280             : #endif
    1281             : 
    1282      988655 :         if ((fd == -1) && (errno == ENOTDIR)) {
    1283           0 :                 size_t parsed, len;
    1284             : 
    1285             :                 /*
    1286             :                  * dirfsp does not point at a directory, try a
    1287             :                  * freadlink.
    1288             :                  */
    1289             : 
    1290       33541 :                 status = create_open_symlink_err(mem_ctx,
    1291             :                                                  dirfsp,
    1292             :                                                  NULL,
    1293             :                                                  &symlink_err);
    1294             : 
    1295       33541 :                 if (!NT_STATUS_IS_OK(status)) {
    1296          24 :                         DBG_DEBUG("create_open_symlink_err failed: %s\n",
    1297             :                                   nt_errstr(status));
    1298          24 :                         status = NT_STATUS_NOT_A_DIRECTORY;
    1299          24 :                         goto fail;
    1300             :                 }
    1301             : 
    1302       33517 :                 parsed = rel_fname.base_name - path;
    1303       33517 :                 len = talloc_get_size(path);
    1304       33517 :                 symlink_err->unparsed = len - parsed;
    1305             : 
    1306       33517 :                 symlink_err->st = dirfsp->fsp_name->st;
    1307             : 
    1308       33517 :                 status = NT_STATUS_STOPPED_ON_SYMLINK;
    1309       33517 :                 goto fail;
    1310             :         }
    1311             : 
    1312      955114 :         if (fd == -1) {
    1313        1210 :                 status = map_nt_error_from_unix(errno);
    1314        1210 :                 DBG_DEBUG("SMB_VFS_OPENAT() failed: %s\n",
    1315             :                           strerror(errno));
    1316        1210 :                 goto fail;
    1317             :         }
    1318      953904 :         fsp_set_fd(fsp, fd);
    1319             : 
    1320      953904 :         ok = full_path_extend(&full_fname.base_name, rel_fname.base_name);
    1321      953904 :         if (!ok) {
    1322           0 :                 goto nomem;
    1323             :         }
    1324             : 
    1325      953904 :         if (next != NULL) {
    1326      170650 :                 struct files_struct *tmp = NULL;
    1327             : 
    1328      170650 :                 if (dirfsp != in_dirfsp) {
    1329       21124 :                         fd_close(dirfsp);
    1330             :                 }
    1331             : 
    1332      170650 :                 tmp = dirfsp;
    1333      170650 :                 dirfsp = fsp;
    1334             : 
    1335      170650 :                 if (tmp == in_dirfsp) {
    1336      149526 :                         status = fsp_new(conn, conn, &fsp);
    1337      149526 :                         if (!NT_STATUS_IS_OK(status)) {
    1338           0 :                                 DBG_DEBUG("fsp_new() failed: %s\n",
    1339             :                                           nt_errstr(status));
    1340           0 :                                 goto fail;
    1341             :                         }
    1342      149526 :                         fsp->fsp_name = &full_fname;
    1343             :                 } else {
    1344       21124 :                         fsp = tmp;
    1345             :                 }
    1346             : 
    1347      170650 :                 rel_fname.base_name = next;
    1348             : 
    1349      170650 :                 goto next;
    1350             :         }
    1351             : 
    1352      783254 :         if (dirfsp != in_dirfsp) {
    1353      109017 :                 SMB_ASSERT(fsp_get_pathref_fd(dirfsp) != -1);
    1354      109017 :                 fd_close(dirfsp);
    1355      109017 :                 dirfsp->fsp_name = NULL;
    1356      109017 :                 file_free(NULL, dirfsp);
    1357      109017 :                 dirfsp = NULL;
    1358             :         }
    1359             : 
    1360      674237 : done:
    1361     1404235 :         fsp->fsp_flags.is_pathref = true;
    1362     1404235 :         fsp->fsp_name = NULL;
    1363             : 
    1364     1404235 :         status = fsp_set_smb_fname(fsp, &full_fname);
    1365     1404235 :         if (!NT_STATUS_IS_OK(status)) {
    1366           0 :                 DBG_DEBUG("fsp_set_smb_fname() failed: %s\n",
    1367             :                           nt_errstr(status));
    1368           0 :                 goto fail;
    1369             :         }
    1370             : 
    1371     1404235 :         status = vfs_stat_fsp(fsp);
    1372     1404235 :         if (!NT_STATUS_IS_OK(status)) {
    1373           0 :                 DBG_DEBUG("vfs_stat_fsp(%s) failed: %s\n",
    1374             :                           fsp_str_dbg(fsp),
    1375             :                           nt_errstr(status));
    1376           0 :                 goto fail;
    1377             :         }
    1378             : 
    1379     1404235 :         if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
    1380             :                 /*
    1381             :                  * Last component was a symlink we opened with O_PATH, fail it
    1382             :                  * here.
    1383             :                  */
    1384        5192 :                 status = create_open_symlink_err(mem_ctx,
    1385             :                                                  fsp,
    1386             :                                                  NULL,
    1387             :                                                  &symlink_err);
    1388        5192 :                 if (!NT_STATUS_IS_OK(status)) {
    1389           0 :                         return status;
    1390             :                 }
    1391        5192 :                 symlink_err->st = fsp->fsp_name->st;
    1392             : 
    1393        5192 :                 status = NT_STATUS_STOPPED_ON_SYMLINK;
    1394        5192 :                 goto fail;
    1395             :         }
    1396             : 
    1397             :         /*
    1398             :          * We must correctly set fsp->file_id as code inside
    1399             :          * open.c will use this to check if delete_on_close
    1400             :          * has been set on the dirfsp.
    1401             :          */
    1402     1399043 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
    1403             : 
    1404     1399043 :         result = cp_smb_filename(mem_ctx, fsp->fsp_name);
    1405     1399043 :         if (result == NULL) {
    1406           0 :                 DBG_DEBUG("cp_smb_filename() failed\n");
    1407           0 :                 goto nomem;
    1408             :         }
    1409             : 
    1410     1399043 :         status = fsp_smb_fname_link(fsp,
    1411             :                                         &result->fsp_link,
    1412             :                                         &result->fsp);
    1413     1399043 :         if (!NT_STATUS_IS_OK(status)) {
    1414           0 :                 goto fail;
    1415             :         }
    1416     1399043 :         talloc_set_destructor(result, smb_fname_fsp_destructor);
    1417             : 
    1418     1399043 :         *_smb_fname = result;
    1419             : 
    1420     1399043 :         DBG_DEBUG("returning %s\n", smb_fname_str_dbg(result));
    1421             : 
    1422     1399043 :         return NT_STATUS_OK;
    1423             : 
    1424           0 : nomem:
    1425           0 :         status = NT_STATUS_NO_MEMORY;
    1426       65895 : fail:
    1427       65895 :         if (fsp != NULL) {
    1428       65895 :                 if (fsp_get_pathref_fd(fsp) != -1) {
    1429        5192 :                         fd_close(fsp);
    1430             :                 }
    1431       65895 :                 file_free(NULL, fsp);
    1432       65895 :                 fsp = NULL;
    1433             :         }
    1434             : 
    1435       65895 :         if ((dirfsp != NULL) && (dirfsp != in_dirfsp)) {
    1436       40509 :                 SMB_ASSERT(fsp_get_pathref_fd(dirfsp) != -1);
    1437       40509 :                 fd_close(dirfsp);
    1438       40509 :                 dirfsp->fsp_name = NULL;
    1439       40509 :                 file_free(NULL, dirfsp);
    1440       40509 :                 dirfsp = NULL;
    1441             :         }
    1442             : 
    1443       65895 :         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
    1444       64508 :                 *_symlink_err = symlink_err;
    1445             :         }
    1446             : 
    1447       65895 :         TALLOC_FREE(path);
    1448       65895 :         return status;
    1449             : }
    1450             : 
    1451             : /*
    1452             :  * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
    1453             :  * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
    1454             :  * the first attempt based on the filename sent by the client gives
    1455             :  * ENOENT.
    1456             :  */
    1457      620162 : NTSTATUS openat_pathref_fsp_lcomp(struct files_struct *dirfsp,
    1458             :                                   struct smb_filename *smb_fname_rel,
    1459             :                                   uint32_t ucf_flags)
    1460             : {
    1461      620162 :         struct connection_struct *conn = dirfsp->conn;
    1462      620162 :         const char *orig_rel_base_name = smb_fname_rel->base_name;
    1463      620162 :         struct files_struct *fsp = NULL;
    1464      620162 :         struct smb_filename *full_fname = NULL;
    1465      620162 :         struct vfs_open_how how = {
    1466             :                 .flags = O_RDONLY | O_NONBLOCK | O_NOFOLLOW,
    1467             :         };
    1468       10404 :         NTSTATUS status;
    1469       10404 :         int ret, fd;
    1470             : 
    1471             :         /*
    1472             :          * Make sure we don't need of the all the magic in
    1473             :          * openat_pathref_fsp() with regards non_widelink_open etc.
    1474             :          */
    1475             : 
    1476      620162 :         SMB_ASSERT((smb_fname_rel->fsp == NULL) &&
    1477             :                    (dirfsp != dirfsp->conn->cwd_fsp) &&
    1478             :                    (strchr_m(smb_fname_rel->base_name, '/') == NULL) &&
    1479             :                    !is_named_stream(smb_fname_rel));
    1480             : 
    1481      620162 :         SET_STAT_INVALID(smb_fname_rel->st);
    1482             : 
    1483             :         /* Check veto files - only looks at last component. */
    1484      620162 :         if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
    1485          14 :                 DBG_DEBUG("veto files rejecting last component %s\n",
    1486             :                           smb_fname_str_dbg(smb_fname_rel));
    1487          14 :                 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
    1488             :         }
    1489             : 
    1490      620148 :         status = fsp_new(conn, conn, &fsp);
    1491      620148 :         if (!NT_STATUS_IS_OK(status)) {
    1492           0 :                 DBG_DEBUG("fsp_new() failed: %s\n", nt_errstr(status));
    1493           0 :                 return status;
    1494             :         }
    1495             : 
    1496      620148 :         GetTimeOfDay(&fsp->open_time);
    1497      620148 :         fsp_set_gen_id(fsp);
    1498      620148 :         ZERO_STRUCT(conn->sconn->fsp_fi_cache);
    1499             : 
    1500      620148 :         fsp->fsp_flags.is_pathref = true;
    1501             : 
    1502      620148 :         full_fname = full_path_from_dirfsp_atname(conn, dirfsp, smb_fname_rel);
    1503      620148 :         if (full_fname == NULL) {
    1504           0 :                 DBG_DEBUG("full_path_from_dirfsp_atname(%s/%s) failed\n",
    1505             :                           dirfsp->fsp_name->base_name,
    1506             :                           smb_fname_rel->base_name);
    1507           0 :                 file_free(NULL, fsp);
    1508           0 :                 return NT_STATUS_NO_MEMORY;
    1509             :         }
    1510             : 
    1511      620148 :         status = fsp_attach_smb_fname(fsp, &full_fname);
    1512      620148 :         if (!NT_STATUS_IS_OK(status)) {
    1513           0 :                 DBG_DEBUG("fsp_attach_smb_fname(fsp, %s) failed: %s\n",
    1514             :                           smb_fname_str_dbg(full_fname),
    1515             :                           nt_errstr(status));
    1516           0 :                 file_free(NULL, fsp);
    1517           0 :                 return status;
    1518             :         }
    1519             : 
    1520     1229892 :         fd = smb_vfs_openat_ci(smb_fname_rel,
    1521     1225608 :                                (ucf_flags & UCF_POSIX_PATHNAMES) ||
    1522      615864 :                                        conn->case_sensitive,
    1523             :                                conn,
    1524             :                                dirfsp,
    1525             :                                smb_fname_rel,
    1526             :                                fsp,
    1527             :                                &how);
    1528             : 
    1529      620148 :         if ((fd == -1) && (errno == ENOENT)) {
    1530      269228 :                 status = map_nt_error_from_unix(errno);
    1531      269228 :                 DBG_DEBUG("smb_vfs_openat(%s/%s) failed: %s\n",
    1532             :                           dirfsp->fsp_name->base_name,
    1533             :                           smb_fname_rel->base_name,
    1534             :                           strerror(errno));
    1535      269228 :                 file_free(NULL, fsp);
    1536      269228 :                 return status;
    1537             :         }
    1538             : 
    1539      350920 :         if (smb_fname_rel->base_name != orig_rel_base_name) {
    1540         422 :                 struct smb_filename new_fullname = *smb_fname_rel;
    1541             : 
    1542         422 :                 DBG_DEBUG("rel->base_name changed from %s to %s\n",
    1543             :                           orig_rel_base_name,
    1544             :                           smb_fname_rel->base_name);
    1545             : 
    1546         422 :                 new_fullname.base_name = full_path_from_dirfsp_at_basename(
    1547         422 :                         talloc_tos(), dirfsp, new_fullname.base_name);
    1548         422 :                 if (new_fullname.base_name == NULL) {
    1549           0 :                         fd_close(fsp);
    1550           0 :                         file_free(NULL, fsp);
    1551           0 :                         return NT_STATUS_NO_MEMORY;
    1552             :                 }
    1553             : 
    1554         422 :                 status = fsp_set_smb_fname(fsp, &new_fullname);
    1555         422 :                 if (!NT_STATUS_IS_OK(status)) {
    1556           0 :                         fd_close(fsp);
    1557           0 :                         file_free(NULL, fsp);
    1558           0 :                         return status;
    1559             :                 }
    1560             :         }
    1561             : 
    1562      350920 :         fsp_set_fd(fsp, fd);
    1563             : 
    1564      350920 :         if (fd >= 0) {
    1565      346795 :                 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
    1566             :         } else {
    1567        4125 :                 ret = SMB_VFS_FSTATAT(fsp->conn,
    1568             :                                       dirfsp,
    1569             :                                       smb_fname_rel,
    1570             :                                       &fsp->fsp_name->st,
    1571             :                                       AT_SYMLINK_NOFOLLOW);
    1572             :         }
    1573      350920 :         if (ret == -1) {
    1574          12 :                 status = map_nt_error_from_unix(errno);
    1575          12 :                 DBG_DEBUG("SMB_VFS_%sSTAT(%s/%s) failed: %s\n",
    1576             :                           (fd >= 0) ? "F" : "",
    1577             :                           dirfsp->fsp_name->base_name,
    1578             :                           smb_fname_rel->base_name,
    1579             :                           nt_errstr(status));
    1580          12 :                 fd_close(fsp);
    1581          12 :                 file_free(NULL, fsp);
    1582          12 :                 return status;
    1583             :         }
    1584             : 
    1585      350908 :         fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
    1586      350908 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
    1587             : 
    1588      350908 :         smb_fname_rel->st = fsp->fsp_name->st;
    1589             : 
    1590      350908 :         status = fsp_smb_fname_link(fsp,
    1591             :                                     &smb_fname_rel->fsp_link,
    1592             :                                     &smb_fname_rel->fsp);
    1593      350908 :         if (!NT_STATUS_IS_OK(status)) {
    1594           0 :                 DBG_DEBUG("fsp_smb_fname_link() failed: %s\n",
    1595             :                           nt_errstr(status));
    1596           0 :                 fd_close(fsp);
    1597           0 :                 file_free(NULL, fsp);
    1598           0 :                 return status;
    1599             :         }
    1600             : 
    1601      350908 :         DBG_DEBUG("fsp [%s]: OK, fd=%d\n", fsp_str_dbg(fsp), fd);
    1602             : 
    1603      350908 :         talloc_set_destructor(smb_fname_rel, smb_fname_fsp_destructor);
    1604      350908 :         return NT_STATUS_OK;
    1605             : }
    1606             : 
    1607     1848840 : void smb_fname_fsp_unlink(struct smb_filename *smb_fname)
    1608             : {
    1609     1848840 :         talloc_set_destructor(smb_fname, NULL);
    1610     1848840 :         smb_fname->fsp = NULL;
    1611     1848840 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
    1612     1848840 : }
    1613             : 
    1614             : /*
    1615             :  * Move any existing embedded fsp refs from the src name to the
    1616             :  * destination. It's safe to call this on src smb_fname's that have no embedded
    1617             :  * pathref fsp.
    1618             :  */
    1619      347099 : NTSTATUS move_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,
    1620             :                                  struct smb_filename *smb_fname_src)
    1621             : {
    1622        9527 :         NTSTATUS status;
    1623             : 
    1624             :         /*
    1625             :          * The target should always not be linked yet!
    1626             :          */
    1627      347099 :         SMB_ASSERT(smb_fname_dst->fsp == NULL);
    1628      347099 :         SMB_ASSERT(smb_fname_dst->fsp_link == NULL);
    1629             : 
    1630      347099 :         if (smb_fname_src->fsp == NULL) {
    1631           0 :                 return NT_STATUS_OK;
    1632             :         }
    1633             : 
    1634      347099 :         status = fsp_smb_fname_link(smb_fname_src->fsp,
    1635             :                                     &smb_fname_dst->fsp_link,
    1636             :                                     &smb_fname_dst->fsp);
    1637      347099 :         if (!NT_STATUS_IS_OK(status)) {
    1638           0 :                 return status;
    1639             :         }
    1640             : 
    1641      347099 :         talloc_set_destructor(smb_fname_dst, smb_fname_fsp_destructor);
    1642             : 
    1643      347099 :         smb_fname_fsp_unlink(smb_fname_src);
    1644             : 
    1645      347099 :         return NT_STATUS_OK;
    1646             : }
    1647             : 
    1648      171250 : static int fsp_ref_no_close_destructor(struct smb_filename *smb_fname)
    1649             : {
    1650      171250 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
    1651      171250 :         return 0;
    1652             : }
    1653             : 
    1654      175587 : NTSTATUS reference_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,
    1655             :                                       const struct smb_filename *smb_fname_src)
    1656             : {
    1657         375 :         NTSTATUS status;
    1658             : 
    1659             :         /*
    1660             :          * The target should always not be linked yet!
    1661             :          */
    1662      175587 :         SMB_ASSERT(smb_fname_dst->fsp == NULL);
    1663      175587 :         SMB_ASSERT(smb_fname_dst->fsp_link == NULL);
    1664             : 
    1665      175587 :         if (smb_fname_src->fsp == NULL) {
    1666        4337 :                 return NT_STATUS_OK;
    1667             :         }
    1668             : 
    1669      171250 :         status = fsp_smb_fname_link(smb_fname_src->fsp,
    1670             :                                     &smb_fname_dst->fsp_link,
    1671             :                                     &smb_fname_dst->fsp);
    1672      171250 :         if (!NT_STATUS_IS_OK(status)) {
    1673           0 :                 return status;
    1674             :         }
    1675             : 
    1676      171250 :         talloc_set_destructor(smb_fname_dst, fsp_ref_no_close_destructor);
    1677             : 
    1678      171250 :         return NT_STATUS_OK;
    1679             : }
    1680             : 
    1681             : /**
    1682             :  * Create an smb_fname and open smb_fname->fsp pathref
    1683             :  **/
    1684      341831 : NTSTATUS synthetic_pathref(TALLOC_CTX *mem_ctx,
    1685             :                            struct files_struct *dirfsp,
    1686             :                            const char *base_name,
    1687             :                            const char *stream_name,
    1688             :                            const SMB_STRUCT_STAT *psbuf,
    1689             :                            NTTIME twrp,
    1690             :                            uint32_t flags,
    1691             :                            struct smb_filename **_smb_fname)
    1692             : {
    1693      341831 :         struct smb_filename *smb_fname = NULL;
    1694        1958 :         NTSTATUS status;
    1695             : 
    1696      341831 :         smb_fname = synthetic_smb_fname(mem_ctx,
    1697             :                                         base_name,
    1698             :                                         stream_name,
    1699             :                                         psbuf,
    1700             :                                         twrp,
    1701             :                                         flags);
    1702      341831 :         if (smb_fname == NULL) {
    1703           0 :                 return NT_STATUS_NO_MEMORY;
    1704             :         }
    1705             : 
    1706      341831 :         status = openat_pathref_fsp(dirfsp, smb_fname);
    1707      341831 :         if (!NT_STATUS_IS_OK(status)) {
    1708      207261 :                 DBG_NOTICE("opening [%s] failed\n",
    1709             :                         smb_fname_str_dbg(smb_fname));
    1710      207261 :                 TALLOC_FREE(smb_fname);
    1711      207261 :                 return status;
    1712             :         }
    1713             : 
    1714      134570 :         *_smb_fname = smb_fname;
    1715      134570 :         return NT_STATUS_OK;
    1716             : }
    1717             : 
    1718             : /**
    1719             :  * Turn a path into a parent pathref and atname
    1720             :  *
    1721             :  * This returns the parent pathref in _parent and the name relative to it. If
    1722             :  * smb_fname was a pathref (ie smb_fname->fsp != NULL), then _atname will be a
    1723             :  * pathref as well, ie _atname->fsp will point at the same fsp as
    1724             :  * smb_fname->fsp.
    1725             :  **/
    1726      174655 : NTSTATUS parent_pathref(TALLOC_CTX *mem_ctx,
    1727             :                         struct files_struct *dirfsp,
    1728             :                         const struct smb_filename *smb_fname,
    1729             :                         struct smb_filename **_parent,
    1730             :                         struct smb_filename **_atname)
    1731             : {
    1732      174655 :         struct smb_filename *parent = NULL;
    1733      174655 :         struct smb_filename *atname = NULL;
    1734         359 :         NTSTATUS status;
    1735             : 
    1736      174655 :         status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
    1737             :                                          mem_ctx,
    1738             :                                          smb_fname,
    1739             :                                          &parent,
    1740             :                                          &atname);
    1741      174655 :         if (!NT_STATUS_IS_OK(status)) {
    1742           0 :                 return status;
    1743             :         }
    1744             : 
    1745             :         /*
    1746             :          * We know that the parent name must
    1747             :          * exist, and the name has been canonicalized
    1748             :          * even if this was a POSIX pathname.
    1749             :          * Ensure that we follow symlinks for
    1750             :          * the parent. See the torture test
    1751             :          * POSIX-SYMLINK-PARENT for details.
    1752             :          */
    1753      174655 :         parent->flags &= ~SMB_FILENAME_POSIX_PATH;
    1754             : 
    1755      174655 :         status = openat_pathref_fsp(dirfsp, parent);
    1756      174655 :         if (!NT_STATUS_IS_OK(status)) {
    1757           0 :                 TALLOC_FREE(parent);
    1758           0 :                 return status;
    1759             :         }
    1760             : 
    1761      174655 :         status = reference_smb_fname_fsp_link(atname, smb_fname);
    1762      174655 :         if (!NT_STATUS_IS_OK(status)) {
    1763           0 :                 TALLOC_FREE(parent);
    1764           0 :                 return status;
    1765             :         }
    1766             : 
    1767      174655 :         *_parent = parent;
    1768      174655 :         *_atname = atname;
    1769      174655 :         return NT_STATUS_OK;
    1770             : }
    1771             : 
    1772        3030 : static bool close_file_in_loop(struct files_struct *fsp,
    1773             :                                enum file_close_type close_type)
    1774             : {
    1775        3030 :         if (fsp_is_alternate_stream(fsp)) {
    1776             :                 /*
    1777             :                  * This is a stream, it can't be a base
    1778             :                  */
    1779          72 :                 SMB_ASSERT(fsp->stream_fsp == NULL);
    1780          72 :                 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
    1781             : 
    1782             :                 /*
    1783             :                  * Remove the base<->stream link so that
    1784             :                  * close_file_free() does not close fsp->base_fsp as
    1785             :                  * well. This would destroy walking the linked list of
    1786             :                  * fsps.
    1787             :                  */
    1788          72 :                 fsp->base_fsp->stream_fsp = NULL;
    1789          72 :                 fsp->base_fsp = NULL;
    1790             : 
    1791          72 :                 close_file_free(NULL, &fsp, close_type);
    1792          72 :                 return NULL;
    1793             :         }
    1794             : 
    1795        2958 :         if (fsp->stream_fsp != NULL) {
    1796             :                 /*
    1797             :                  * This is the base of a stream.
    1798             :                  */
    1799           0 :                 SMB_ASSERT(fsp->stream_fsp->base_fsp == fsp);
    1800             : 
    1801             :                 /*
    1802             :                  * Remove the base<->stream link. This will make fsp
    1803             :                  * look like a normal fsp for the next round.
    1804             :                  */
    1805           0 :                 fsp->stream_fsp->base_fsp = NULL;
    1806           0 :                 fsp->stream_fsp = NULL;
    1807             : 
    1808             :                 /*
    1809             :                  * Have us called back a second time. In the second
    1810             :                  * round, "fsp" now looks like a normal fsp.
    1811             :                  */
    1812           0 :                 return false;
    1813             :         }
    1814             : 
    1815        2958 :         close_file_free(NULL, &fsp, close_type);
    1816        2958 :         return true;
    1817             : }
    1818             : 
    1819             : /****************************************************************************
    1820             :  Close all open files for a connection.
    1821             : ****************************************************************************/
    1822             : 
    1823             : struct file_close_conn_state {
    1824             :         struct connection_struct *conn;
    1825             :         enum file_close_type close_type;
    1826             :         bool fsp_left_behind;
    1827             : };
    1828             : 
    1829        1611 : static struct files_struct *file_close_conn_fn(
    1830             :         struct files_struct *fsp,
    1831             :         void *private_data)
    1832             : {
    1833        1611 :         struct file_close_conn_state *state = private_data;
    1834           8 :         bool did_close;
    1835             : 
    1836        1611 :         if (fsp->conn != state->conn) {
    1837        1171 :                 return NULL;
    1838             :         }
    1839             : 
    1840         438 :         if (fsp->op != NULL && fsp->op->global->durable) {
    1841             :                 /*
    1842             :                  * A tree disconnect closes a durable handle
    1843             :                  */
    1844           4 :                 fsp->op->global->durable = false;
    1845             :         }
    1846             : 
    1847         438 :         did_close = close_file_in_loop(fsp, state->close_type);
    1848         438 :         if (!did_close) {
    1849           0 :                 state->fsp_left_behind = true;
    1850             :         }
    1851             : 
    1852         432 :         return NULL;
    1853             : }
    1854             : 
    1855       47082 : void file_close_conn(connection_struct *conn, enum file_close_type close_type)
    1856             : {
    1857       47082 :         struct file_close_conn_state state = { .conn = conn,
    1858             :                                                .close_type = close_type };
    1859             : 
    1860       47082 :         files_forall(conn->sconn, file_close_conn_fn, &state);
    1861             : 
    1862       47082 :         if (state.fsp_left_behind) {
    1863           0 :                 state.fsp_left_behind = false;
    1864           0 :                 files_forall(conn->sconn, file_close_conn_fn, &state);
    1865           0 :                 SMB_ASSERT(!state.fsp_left_behind);
    1866             :         }
    1867       47082 : }
    1868             : 
    1869             : /****************************************************************************
    1870             :  Initialise file structures.
    1871             : ****************************************************************************/
    1872             : 
    1873             : static int files_max_open_fds;
    1874             : 
    1875       30685 : bool file_init_global(void)
    1876             : {
    1877       30685 :         int request_max = lp_max_open_files();
    1878         842 :         int real_lim;
    1879         842 :         int real_max;
    1880             : 
    1881       30685 :         if (files_max_open_fds != 0) {
    1882       29825 :                 return true;
    1883             :         }
    1884             : 
    1885             :         /*
    1886             :          * Set the max_open files to be the requested
    1887             :          * max plus a fudgefactor to allow for the extra
    1888             :          * fd's we need such as log files etc...
    1889             :          */
    1890          18 :         real_lim = set_maxfiles(request_max + MAX_OPEN_FUDGEFACTOR);
    1891             : 
    1892          18 :         real_max = real_lim - MAX_OPEN_FUDGEFACTOR;
    1893             : 
    1894          18 :         if (real_max + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536) {
    1895           0 :                 real_max = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
    1896             :         }
    1897             : 
    1898          18 :         if (real_max != request_max) {
    1899           0 :                 DEBUG(1, ("file_init_global: Information only: requested %d "
    1900             :                           "open files, %d are available.\n",
    1901             :                           request_max, real_max));
    1902             :         }
    1903             : 
    1904          18 :         SMB_ASSERT(real_max > 100);
    1905             : 
    1906          18 :         files_max_open_fds = real_max;
    1907          18 :         return true;
    1908             : }
    1909             : 
    1910       30685 : bool file_init(struct smbd_server_connection *sconn)
    1911             : {
    1912         842 :         bool ok;
    1913             : 
    1914       30685 :         ok = file_init_global();
    1915       30685 :         if (!ok) {
    1916           0 :                 return false;
    1917             :         }
    1918             : 
    1919       30685 :         sconn->real_max_open_files = files_max_open_fds;
    1920             : 
    1921       30685 :         return true;
    1922             : }
    1923             : 
    1924             : /****************************************************************************
    1925             :  Close files open by a specified vuid.
    1926             : ****************************************************************************/
    1927             : 
    1928             : struct file_close_user_state {
    1929             :         uint64_t vuid;
    1930             :         bool fsp_left_behind;
    1931             : };
    1932             : 
    1933        2818 : static struct files_struct *file_close_user_fn(
    1934             :         struct files_struct *fsp,
    1935             :         void *private_data)
    1936             : {
    1937        2818 :         struct file_close_user_state *state = private_data;
    1938         277 :         bool did_close;
    1939             : 
    1940        2818 :         if (fsp->vuid != state->vuid) {
    1941         224 :                 return NULL;
    1942             :         }
    1943             : 
    1944        2592 :         did_close = close_file_in_loop(fsp, SHUTDOWN_CLOSE);
    1945        2592 :         if (!did_close) {
    1946          72 :                 state->fsp_left_behind = true;
    1947             :         }
    1948             : 
    1949        2317 :         return NULL;
    1950             : }
    1951             : 
    1952       31116 : void file_close_user(struct smbd_server_connection *sconn, uint64_t vuid)
    1953             : {
    1954       31116 :         struct file_close_user_state state = { .vuid = vuid };
    1955             : 
    1956       31116 :         files_forall(sconn, file_close_user_fn, &state);
    1957             : 
    1958       31116 :         if (state.fsp_left_behind) {
    1959          36 :                 state.fsp_left_behind = false;
    1960          36 :                 files_forall(sconn, file_close_user_fn, &state);
    1961          36 :                 SMB_ASSERT(!state.fsp_left_behind);
    1962             :         }
    1963       31116 : }
    1964             : 
    1965             : /*
    1966             :  * Walk the files table until "fn" returns non-NULL
    1967             :  */
    1968             : 
    1969      230746 : struct files_struct *files_forall(
    1970             :         struct smbd_server_connection *sconn,
    1971             :         struct files_struct *(*fn)(struct files_struct *fsp,
    1972             :                                    void *private_data),
    1973             :         void *private_data)
    1974             : {
    1975        1889 :         struct files_struct *fsp, *next;
    1976             : 
    1977      455720 :         for (fsp = sconn->files; fsp; fsp = next) {
    1978         360 :                 struct files_struct *ret;
    1979      226953 :                 next = fsp->next;
    1980      226953 :                 ret = fn(fsp, private_data);
    1981      226953 :                 if (ret != NULL) {
    1982        1979 :                         return ret;
    1983             :                 }
    1984             :         }
    1985      226892 :         return NULL;
    1986             : }
    1987             : 
    1988             : /****************************************************************************
    1989             :  Find a fsp given a file descriptor.
    1990             : ****************************************************************************/
    1991             : 
    1992           4 : files_struct *file_find_fd(struct smbd_server_connection *sconn, int fd)
    1993             : {
    1994           4 :         int count=0;
    1995           0 :         files_struct *fsp;
    1996             : 
    1997           5 :         for (fsp=sconn->files; fsp; fsp=fsp->next,count++) {
    1998           5 :                 if (fsp_get_pathref_fd(fsp) == fd) {
    1999           4 :                         if (count > 10) {
    2000           0 :                                 DLIST_PROMOTE(sconn->files, fsp);
    2001             :                         }
    2002           4 :                         return fsp;
    2003             :                 }
    2004             :         }
    2005             : 
    2006           0 :         return NULL;
    2007             : }
    2008             : 
    2009             : /****************************************************************************
    2010             :  Find a fsp given a device, inode and file_id.
    2011             : ****************************************************************************/
    2012             : 
    2013       14623 : files_struct *file_find_dif(struct smbd_server_connection *sconn,
    2014             :                             struct file_id id, unsigned long gen_id)
    2015             : {
    2016       14623 :         int count=0;
    2017          71 :         files_struct *fsp;
    2018             : 
    2019       14623 :         if (gen_id == 0) {
    2020           0 :                 return NULL;
    2021             :         }
    2022             : 
    2023      202879 :         for (fsp = sconn->files; fsp; fsp = fsp->next,count++) {
    2024             :                 /*
    2025             :                  * We can have a fsp->fh->fd == -1 here as it could be a stat
    2026             :                  * open.
    2027             :                  */
    2028      202879 :                 if (!file_id_equal(&fsp->file_id, &id)) {
    2029       17096 :                         continue;
    2030             :                 }
    2031      185783 :                 if (!fsp->fsp_flags.is_fsa) {
    2032       14642 :                         continue;
    2033             :                 }
    2034      171141 :                 if (fh_get_gen_id(fsp->fh) != gen_id) {
    2035      156518 :                         continue;
    2036             :                 }
    2037       14623 :                 if (count > 10) {
    2038        4646 :                         DLIST_PROMOTE(sconn->files, fsp);
    2039             :                 }
    2040       14552 :                 return fsp;
    2041             :         }
    2042             : 
    2043           0 :         return NULL;
    2044             : }
    2045             : 
    2046             : /****************************************************************************
    2047             :  Find the first fsp given a device and inode.
    2048             :  We use a singleton cache here to speed up searching from getfilepathinfo
    2049             :  calls.
    2050             : ****************************************************************************/
    2051             : 
    2052       11600 : files_struct *file_find_di_first(struct smbd_server_connection *sconn,
    2053             :                                  struct file_id id,
    2054             :                                  bool need_fsa)
    2055             : {
    2056         301 :         files_struct *fsp;
    2057             : 
    2058       11600 :         if (file_id_equal(&sconn->fsp_fi_cache.id, &id)) {
    2059             :                 /* Positive or negative cache hit. */
    2060           0 :                 return sconn->fsp_fi_cache.fsp;
    2061             :         }
    2062             : 
    2063       11600 :         sconn->fsp_fi_cache.id = id;
    2064             : 
    2065       37436 :         for (fsp=sconn->files;fsp;fsp=fsp->next) {
    2066       29611 :                 if (need_fsa && !fsp->fsp_flags.is_fsa) {
    2067       19611 :                         continue;
    2068             :                 }
    2069       10000 :                 if (file_id_equal(&fsp->file_id, &id)) {
    2070             :                         /* Setup positive cache. */
    2071        3775 :                         sconn->fsp_fi_cache.fsp = fsp;
    2072        3775 :                         return fsp;
    2073             :                 }
    2074             :         }
    2075             : 
    2076             :         /* Setup negative cache. */
    2077        7825 :         sconn->fsp_fi_cache.fsp = NULL;
    2078        7825 :         return NULL;
    2079             : }
    2080             : 
    2081             : /****************************************************************************
    2082             :  Find the next fsp having the same device and inode.
    2083             : ****************************************************************************/
    2084             : 
    2085        2069 : files_struct *file_find_di_next(files_struct *start_fsp,
    2086             :                                 bool need_fsa)
    2087             : {
    2088          21 :         files_struct *fsp;
    2089             : 
    2090        2891 :         for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
    2091         977 :                 if (need_fsa && !fsp->fsp_flags.is_fsa) {
    2092           0 :                         continue;
    2093             :                 }
    2094         977 :                 if (file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
    2095         155 :                         return fsp;
    2096             :                 }
    2097             :         }
    2098             : 
    2099        1898 :         return NULL;
    2100             : }
    2101             : 
    2102           4 : struct files_struct *file_find_one_fsp_from_lease_key(
    2103             :         struct smbd_server_connection *sconn,
    2104             :         const struct smb2_lease_key *lease_key)
    2105             : {
    2106           0 :         struct files_struct *fsp;
    2107             : 
    2108           6 :         for (fsp = sconn->files; fsp; fsp=fsp->next) {
    2109           6 :                 if ((fsp->lease != NULL) &&
    2110           4 :                     (fsp->lease->lease.lease_key.data[0] ==
    2111           4 :                      lease_key->data[0]) &&
    2112           4 :                     (fsp->lease->lease.lease_key.data[1] ==
    2113           4 :                      lease_key->data[1])) {
    2114           4 :                         return fsp;
    2115             :                 }
    2116             :         }
    2117           0 :         return NULL;
    2118             : }
    2119             : 
    2120             : /****************************************************************************
    2121             :  Find any fsp open with a pathname below that of an already open path.
    2122             : ****************************************************************************/
    2123             : 
    2124          19 : bool file_find_subpath(files_struct *dir_fsp)
    2125             : {
    2126           5 :         files_struct *fsp;
    2127           5 :         size_t dlen;
    2128          19 :         char *d_fullname = NULL;
    2129             : 
    2130          19 :         d_fullname = talloc_asprintf(talloc_tos(), "%s/%s",
    2131          19 :                                      dir_fsp->conn->connectpath,
    2132          19 :                                      dir_fsp->fsp_name->base_name);
    2133             : 
    2134          19 :         if (!d_fullname) {
    2135           0 :                 return false;
    2136             :         }
    2137             : 
    2138          19 :         dlen = strlen(d_fullname);
    2139             : 
    2140          86 :         for (fsp=dir_fsp->conn->sconn->files; fsp; fsp=fsp->next) {
    2141          20 :                 char *d1_fullname;
    2142             : 
    2143          70 :                 if (fsp == dir_fsp) {
    2144          19 :                         continue;
    2145             :                 }
    2146             : 
    2147          51 :                 d1_fullname = talloc_asprintf(talloc_tos(),
    2148             :                                         "%s/%s",
    2149          51 :                                         fsp->conn->connectpath,
    2150          51 :                                         fsp->fsp_name->base_name);
    2151             : 
    2152             :                 /*
    2153             :                  * If the open file has a path that is a longer
    2154             :                  * component, then it's a subpath.
    2155             :                  */
    2156          51 :                 if (strnequal(d_fullname, d1_fullname, dlen) &&
    2157          15 :                                 (d1_fullname[dlen] == '/')) {
    2158           3 :                         TALLOC_FREE(d1_fullname);
    2159           3 :                         TALLOC_FREE(d_fullname);
    2160           3 :                         return true;
    2161             :                 }
    2162          53 :                 TALLOC_FREE(d1_fullname);
    2163             :         }
    2164             : 
    2165          16 :         TALLOC_FREE(d_fullname);
    2166          16 :         return false;
    2167             : }
    2168             : 
    2169             : /****************************************************************************
    2170             :  Free up a fsp.
    2171             : ****************************************************************************/
    2172             : 
    2173     6256651 : static void fsp_free(files_struct *fsp)
    2174             : {
    2175     6256651 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
    2176             : 
    2177     6256651 :         if (fsp == sconn->fsp_fi_cache.fsp) {
    2178         517 :                 ZERO_STRUCT(sconn->fsp_fi_cache);
    2179             :         }
    2180             : 
    2181     6256651 :         DLIST_REMOVE(sconn->files, fsp);
    2182     6256651 :         SMB_ASSERT(sconn->num_files > 0);
    2183     6256651 :         sconn->num_files--;
    2184             : 
    2185     6256651 :         TALLOC_FREE(fsp->fake_file_handle);
    2186             : 
    2187     6256651 :         if (fh_get_refcount(fsp->fh) == 1) {
    2188     6256538 :                 TALLOC_FREE(fsp->fh);
    2189             :         } else {
    2190         113 :                 size_t new_refcount = fh_get_refcount(fsp->fh) - 1;
    2191         113 :                 fh_set_refcount(fsp->fh, new_refcount);
    2192             :         }
    2193             : 
    2194     6256651 :         if (fsp->lease != NULL) {
    2195        1024 :                 if (fsp->lease->ref_count == 1) {
    2196         812 :                         TALLOC_FREE(fsp->lease);
    2197             :                 } else {
    2198         212 :                         fsp->lease->ref_count--;
    2199             :                 }
    2200             :         }
    2201             : 
    2202     6256651 :         fsp->conn->num_files_open--;
    2203             : 
    2204     6256651 :         if (fsp->fsp_name != NULL &&
    2205     6107115 :             fsp->fsp_name->fsp_link != NULL)
    2206             :         {
    2207             :                 /*
    2208             :                  * Free fsp_link of fsp->fsp_name. To do this in the correct
    2209             :                  * talloc destructor order we have to do it here. The
    2210             :                  * talloc_free() of the link should set the fsp pointer to NULL.
    2211             :                  */
    2212     6046384 :                 TALLOC_FREE(fsp->fsp_name->fsp_link);
    2213     6046384 :                 SMB_ASSERT(fsp->fsp_name->fsp == NULL);
    2214             :         }
    2215             : 
    2216             :         /* this is paranoia, just in case someone tries to reuse the
    2217             :            information */
    2218     6256651 :         ZERO_STRUCTP(fsp);
    2219             : 
    2220             :         /* fsp->fsp_name is a talloc child and is free'd automatically. */
    2221     6256651 :         TALLOC_FREE(fsp);
    2222     6256651 : }
    2223             : 
    2224             : /*
    2225             :  * Rundown of all smb-related sub-structures of an fsp
    2226             :  */
    2227     6838041 : void fsp_unbind_smb(struct smb_request *req, files_struct *fsp)
    2228             : {
    2229     6838041 :         if (fsp == fsp->conn->cwd_fsp) {
    2230           0 :                 return;
    2231             :         }
    2232             : 
    2233     6838041 :         if (fsp->notify) {
    2234        1866 :                 size_t len = fsp_fullbasepath(fsp, NULL, 0);
    2235        1866 :                 char fullpath[len+1];
    2236             : 
    2237        1866 :                 fsp_fullbasepath(fsp, fullpath, sizeof(fullpath));
    2238             : 
    2239             :                 /*
    2240             :                  * Avoid /. at the end of the path name. notify can't
    2241             :                  * deal with it.
    2242             :                  */
    2243        1866 :                 if (len > 1 && fullpath[len-1] == '.' &&
    2244          96 :                     fullpath[len-2] == '/') {
    2245          96 :                         fullpath[len-2] = '\0';
    2246             :                 }
    2247             : 
    2248        1866 :                 notify_remove(fsp->conn->sconn->notify_ctx, fsp, fullpath);
    2249        1866 :                 TALLOC_FREE(fsp->notify);
    2250             :         }
    2251             : 
    2252             :         /* Ensure this event will never fire. */
    2253     6838041 :         TALLOC_FREE(fsp->update_write_time_event);
    2254             : 
    2255     6838041 :         if (fsp->op != NULL) {
    2256      564475 :                 fsp->op->compat = NULL;
    2257             :         }
    2258     6838041 :         TALLOC_FREE(fsp->op);
    2259             : 
    2260     6838041 :         if ((req != NULL) && (fsp == req->chain_fsp)) {
    2261      552763 :                 req->chain_fsp = NULL;
    2262             :         }
    2263             : 
    2264             :         /*
    2265             :          * Clear all possible chained fsp
    2266             :          * pointers in the SMB2 request queue.
    2267             :          */
    2268     6838041 :         remove_smb2_chained_fsp(fsp);
    2269             : }
    2270             : 
    2271     6256651 : void file_free(struct smb_request *req, files_struct *fsp)
    2272             : {
    2273     6256651 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
    2274     6256651 :         uint64_t fnum = fsp->fnum;
    2275             : 
    2276     6256651 :         fsp_unbind_smb(req, fsp);
    2277             : 
    2278             :         /* Drop all remaining extensions. */
    2279     6256651 :         vfs_remove_all_fsp_extensions(fsp);
    2280             : 
    2281     6256651 :         fsp_free(fsp);
    2282             : 
    2283     6256651 :         DBG_INFO("freed files structure %"PRIu64" (%zu used)\n",
    2284             :                  fnum,
    2285             :                  sconn->num_files);
    2286     6256651 : }
    2287             : 
    2288             : /****************************************************************************
    2289             :  Get an fsp from a packet given a 16 bit fnum.
    2290             : ****************************************************************************/
    2291             : 
    2292      211492 : files_struct *file_fsp(struct smb_request *req, uint16_t fid)
    2293             : {
    2294        1269 :         struct smbXsrv_open *op;
    2295        1269 :         NTSTATUS status;
    2296      211492 :         NTTIME now = 0;
    2297        1269 :         files_struct *fsp;
    2298             : 
    2299      211492 :         if (req == NULL) {
    2300             :                 /*
    2301             :                  * We should never get here. req==NULL could in theory
    2302             :                  * only happen from internal opens with a non-zero
    2303             :                  * root_dir_fid. Internal opens just don't do that, at
    2304             :                  * least they are not supposed to do so. And if they
    2305             :                  * start to do so, they better fake up a smb_request
    2306             :                  * from which we get the right smbd_server_conn. While
    2307             :                  * this should never happen, let's return NULL here.
    2308             :                  */
    2309           0 :                 return NULL;
    2310             :         }
    2311             : 
    2312      211492 :         if (req->chain_fsp != NULL) {
    2313          96 :                 if (req->chain_fsp->fsp_flags.closing) {
    2314           0 :                         return NULL;
    2315             :                 }
    2316          96 :                 return req->chain_fsp;
    2317             :         }
    2318             : 
    2319      211396 :         if (req->xconn == NULL) {
    2320           0 :                 return NULL;
    2321             :         }
    2322             : 
    2323      211396 :         now = timeval_to_nttime(&req->request_time);
    2324             : 
    2325      211396 :         status = smb1srv_open_lookup(req->xconn,
    2326             :                                      fid, now, &op);
    2327      211396 :         if (!NT_STATUS_IS_OK(status)) {
    2328        2688 :                 return NULL;
    2329             :         }
    2330             : 
    2331      208649 :         fsp = op->compat;
    2332      208649 :         if (fsp == NULL) {
    2333           0 :                 return NULL;
    2334             :         }
    2335             : 
    2336      208649 :         if (fsp->fsp_flags.closing) {
    2337           0 :                 return NULL;
    2338             :         }
    2339             : 
    2340      208649 :         req->chain_fsp = fsp;
    2341      208649 :         fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTE_INVALID;
    2342      208649 :         return fsp;
    2343             : }
    2344             : 
    2345      825543 : struct files_struct *file_fsp_get(struct smbd_smb2_request *smb2req,
    2346             :                                   uint64_t persistent_id,
    2347             :                                   uint64_t volatile_id)
    2348             : {
    2349        8371 :         struct smbXsrv_open *op;
    2350        8371 :         NTSTATUS status;
    2351      825543 :         NTTIME now = 0;
    2352        8371 :         struct files_struct *fsp;
    2353             : 
    2354      825543 :         now = timeval_to_nttime(&smb2req->request_time);
    2355             : 
    2356      825543 :         status = smb2srv_open_lookup(smb2req->xconn,
    2357             :                                      persistent_id, volatile_id,
    2358             :                                      now, &op);
    2359      825543 :         if (!NT_STATUS_IS_OK(status)) {
    2360       13510 :                 return NULL;
    2361             :         }
    2362             : 
    2363      812033 :         fsp = op->compat;
    2364      812033 :         if (fsp == NULL) {
    2365           0 :                 return NULL;
    2366             :         }
    2367             : 
    2368      812033 :         if (smb2req->tcon == NULL) {
    2369           0 :                 return NULL;
    2370             :         }
    2371             : 
    2372      812033 :         if (smb2req->tcon->compat != fsp->conn) {
    2373           4 :                 return NULL;
    2374             :         }
    2375             : 
    2376      812029 :         if (smb2req->session == NULL) {
    2377           0 :                 return NULL;
    2378             :         }
    2379             : 
    2380      812029 :         if (smb2req->session->global->session_wire_id != fsp->vuid) {
    2381           0 :                 return NULL;
    2382             :         }
    2383             : 
    2384      812029 :         if (fsp->fsp_flags.closing) {
    2385           0 :                 return NULL;
    2386             :         }
    2387             : 
    2388      812029 :         fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTE_INVALID;
    2389             : 
    2390      812029 :         return fsp;
    2391             : }
    2392             : 
    2393     1637470 : struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
    2394             :                                    uint64_t persistent_id,
    2395             :                                    uint64_t volatile_id)
    2396             : {
    2397       16740 :         struct files_struct *fsp;
    2398             : 
    2399     1637470 :         if (smb2req->compat_chain_fsp != NULL) {
    2400      811927 :                 if (smb2req->compat_chain_fsp->fsp_flags.closing) {
    2401           0 :                         return NULL;
    2402             :                 }
    2403      811927 :                 smb2req->compat_chain_fsp->fsp_name->st.cached_dos_attributes =
    2404             :                         FILE_ATTRIBUTE_INVALID;
    2405      811927 :                 return smb2req->compat_chain_fsp;
    2406             :         }
    2407             : 
    2408      825543 :         fsp = file_fsp_get(smb2req, persistent_id, volatile_id);
    2409      825543 :         if (fsp == NULL) {
    2410       13514 :                 return NULL;
    2411             :         }
    2412             : 
    2413      812029 :         smb2req->compat_chain_fsp = fsp;
    2414      812029 :         return fsp;
    2415             : }
    2416             : 
    2417             : /****************************************************************************
    2418             :  Duplicate the file handle part for a DOS or FCB open.
    2419             : ****************************************************************************/
    2420             : 
    2421         113 : NTSTATUS dup_file_fsp(
    2422             :         files_struct *from,
    2423             :         uint32_t access_mask,
    2424             :         files_struct *to)
    2425             : {
    2426           1 :         size_t new_refcount;
    2427             : 
    2428             :         /* this can never happen for print files */
    2429         113 :         SMB_ASSERT(from->print_file == NULL);
    2430             : 
    2431         113 :         TALLOC_FREE(to->fh);
    2432             : 
    2433         113 :         to->fh = from->fh;
    2434         113 :         new_refcount = fh_get_refcount(to->fh) + 1;
    2435         113 :         fh_set_refcount(to->fh, new_refcount);
    2436             : 
    2437         113 :         to->file_id = from->file_id;
    2438         113 :         to->initial_allocation_size = from->initial_allocation_size;
    2439         113 :         to->file_pid = from->file_pid;
    2440         113 :         to->vuid = from->vuid;
    2441         113 :         to->open_time = from->open_time;
    2442         113 :         to->access_mask = access_mask;
    2443         113 :         to->oplock_type = from->oplock_type;
    2444         113 :         to->fsp_flags.can_lock = from->fsp_flags.can_lock;
    2445         113 :         to->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
    2446         114 :         to->fsp_flags.can_write =
    2447         225 :                 CAN_WRITE(from->conn) &&
    2448         113 :                 ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
    2449         113 :         to->fsp_flags.modified = from->fsp_flags.modified;
    2450         113 :         to->fsp_flags.is_directory = from->fsp_flags.is_directory;
    2451         113 :         to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind;
    2452         113 :         to->fsp_flags.is_fsa = from->fsp_flags.is_fsa;
    2453         113 :         to->fsp_flags.is_pathref = from->fsp_flags.is_pathref;
    2454         113 :         to->fsp_flags.have_proc_fds = from->fsp_flags.have_proc_fds;
    2455         113 :         to->fsp_flags.is_dirfsp = from->fsp_flags.is_dirfsp;
    2456             : 
    2457         113 :         return fsp_set_smb_fname(to, from->fsp_name);
    2458             : }
    2459             : 
    2460             : /**
    2461             :  * Return a jenkins hash of a pathname on a connection.
    2462             :  */
    2463             : 
    2464     6185464 : NTSTATUS file_name_hash(connection_struct *conn,
    2465             :                         const char *name, uint32_t *p_name_hash)
    2466             : {
    2467       32961 :         char tmpbuf[PATH_MAX];
    2468       32961 :         char *fullpath, *to_free;
    2469       32961 :         ssize_t len;
    2470       32961 :         TDB_DATA key;
    2471             : 
    2472             :         /* Set the hash of the full pathname. */
    2473             : 
    2474     6185464 :         if (name[0] == '/') {
    2475     1438401 :                 strlcpy(tmpbuf, name, sizeof(tmpbuf));
    2476     1438401 :                 fullpath = tmpbuf;
    2477     1438401 :                 len = strlen(fullpath);
    2478     1438401 :                 to_free = NULL;
    2479             :         } else {
    2480     4747063 :                 len = full_path_tos(conn->connectpath,
    2481             :                                     name,
    2482             :                                     tmpbuf,
    2483             :                                     sizeof(tmpbuf),
    2484             :                                     &fullpath,
    2485             :                                     &to_free);
    2486             :         }
    2487     6185464 :         if (len == -1) {
    2488           0 :                 return NT_STATUS_NO_MEMORY;
    2489             :         }
    2490     6185464 :         key = (TDB_DATA) { .dptr = (uint8_t *)fullpath, .dsize = len+1 };
    2491     6185464 :         *p_name_hash = tdb_jenkins_hash(&key);
    2492             : 
    2493     6185464 :         DEBUG(10,("file_name_hash: %s hash 0x%x\n",
    2494             :                   fullpath,
    2495             :                 (unsigned int)*p_name_hash ));
    2496             : 
    2497     6185464 :         TALLOC_FREE(to_free);
    2498     6185464 :         return NT_STATUS_OK;
    2499             : }
    2500             : 
    2501     6050226 : static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
    2502             :                                      struct smb_filename **_smb_fname)
    2503             : {
    2504     6050226 :         TALLOC_CTX *frame = talloc_stackframe();
    2505     6050226 :         struct smb_filename *smb_fname_new = talloc_move(fsp, _smb_fname);
    2506     6050226 :         const char *name_str = NULL;
    2507     6050226 :         uint32_t name_hash = 0;
    2508       32311 :         NTSTATUS status;
    2509             : 
    2510     6050226 :         name_str = smb_fname_str_dbg(smb_fname_new);
    2511     6050226 :         if (name_str == NULL) {
    2512           0 :                 TALLOC_FREE(frame);
    2513           0 :                 return NT_STATUS_NO_MEMORY;
    2514             :         }
    2515             : 
    2516     6050226 :         status = file_name_hash(fsp->conn,
    2517             :                                 name_str,
    2518             :                                 &name_hash);
    2519     6050226 :         TALLOC_FREE(frame);
    2520     6050226 :         name_str = NULL;
    2521     6050226 :         if (!NT_STATUS_IS_OK(status)) {
    2522           0 :                 return status;
    2523             :         }
    2524             : 
    2525     6050226 :         status = fsp_smb_fname_link(fsp,
    2526             :                                     &smb_fname_new->fsp_link,
    2527             :                                     &smb_fname_new->fsp);
    2528     6050226 :         if (!NT_STATUS_IS_OK(status)) {
    2529           0 :                 return status;
    2530             :         }
    2531             : 
    2532     6050226 :         fsp->name_hash = name_hash;
    2533     6050226 :         fsp->fsp_name = smb_fname_new;
    2534     6050226 :         fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTE_INVALID;
    2535     6050226 :         *_smb_fname = NULL;
    2536     6050226 :         return NT_STATUS_OK;
    2537             : }
    2538             : 
    2539             : /**
    2540             :  * The only way that the fsp->fsp_name field should ever be set.
    2541             :  */
    2542     1989859 : NTSTATUS fsp_set_smb_fname(struct files_struct *fsp,
    2543             :                            const struct smb_filename *smb_fname_in)
    2544             : {
    2545     1989859 :         struct smb_filename *smb_fname_old = fsp->fsp_name;
    2546     1989859 :         struct smb_filename *smb_fname_new = NULL;
    2547       11206 :         NTSTATUS status;
    2548             : 
    2549     1989859 :         smb_fname_new = cp_smb_filename(fsp, smb_fname_in);
    2550     1989859 :         if (smb_fname_new == NULL) {
    2551           0 :                 return NT_STATUS_NO_MEMORY;
    2552             :         }
    2553             : 
    2554     1989859 :         status = fsp_attach_smb_fname(fsp, &smb_fname_new);
    2555     1989859 :         if (!NT_STATUS_IS_OK(status)) {
    2556           0 :                 TALLOC_FREE(smb_fname_new);
    2557           0 :                 return status;
    2558             :         }
    2559             : 
    2560     1989859 :         if (smb_fname_old != NULL) {
    2561      585494 :                 smb_fname_fsp_unlink(smb_fname_old);
    2562      585494 :                 TALLOC_FREE(smb_fname_old);
    2563             :         }
    2564             : 
    2565     1989859 :         return NT_STATUS_OK;
    2566             : }
    2567             : 
    2568        7466 : size_t fsp_fullbasepath(struct files_struct *fsp, char *buf, size_t buflen)
    2569             : {
    2570        7466 :         int len = 0;
    2571             : 
    2572        7466 :         if ((buf == NULL) || (buflen == 0)) {
    2573        3734 :                 return strlen(fsp->conn->connectpath) + 1 +
    2574        3734 :                        strlen(fsp->fsp_name->base_name);
    2575             :         }
    2576             : 
    2577        3732 :         len = snprintf(buf, buflen, "%s/%s", fsp->conn->connectpath,
    2578        3732 :                        fsp->fsp_name->base_name);
    2579        3732 :         SMB_ASSERT(len>0);
    2580             : 
    2581        3732 :         return len;
    2582             : }
    2583             : 
    2584     4959913 : void fsp_set_base_fsp(struct files_struct *fsp, struct files_struct *base_fsp)
    2585             : {
    2586     4959913 :         SMB_ASSERT(fsp->stream_fsp == NULL);
    2587     4959913 :         if (base_fsp != NULL) {
    2588       15507 :                 SMB_ASSERT(base_fsp->base_fsp == NULL);
    2589       15507 :                 SMB_ASSERT(base_fsp->stream_fsp == NULL);
    2590             :         }
    2591             : 
    2592     4959913 :         if (fsp->base_fsp != NULL) {
    2593        8206 :                 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
    2594        8206 :                 fsp->base_fsp->stream_fsp = NULL;
    2595             :         }
    2596             : 
    2597     4959913 :         fsp->base_fsp = base_fsp;
    2598     4959913 :         if (fsp->base_fsp != NULL) {
    2599       15507 :                 fsp->base_fsp->stream_fsp = fsp;
    2600             :         }
    2601     4959913 : }
    2602             : 
    2603    22419895 : bool fsp_is_alternate_stream(const struct files_struct *fsp)
    2604             : {
    2605    22419895 :         return (fsp->base_fsp != NULL);
    2606             : }
    2607             : 
    2608     3903748 : struct files_struct *metadata_fsp(struct files_struct *fsp)
    2609             : {
    2610     3903748 :         if (fsp_is_alternate_stream(fsp)) {
    2611       16722 :                 return fsp->base_fsp;
    2612             :         }
    2613     3879415 :         return fsp;
    2614             : }
    2615             : 
    2616      410939 : static bool fsp_generic_ask_sharemode(struct files_struct *fsp)
    2617             : {
    2618      410939 :         if (fsp == NULL) {
    2619           0 :                 return false;
    2620             :         }
    2621             : 
    2622      410939 :         if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
    2623             :                 /* Always use filesystem for UNIX mtime query. */
    2624        1596 :                 return false;
    2625             :         }
    2626             : 
    2627      407771 :         return true;
    2628             : }
    2629             : 
    2630       29474 : bool fsp_search_ask_sharemode(struct files_struct *fsp)
    2631             : {
    2632       29474 :         if (!fsp_generic_ask_sharemode(fsp)) {
    2633          38 :                 return false;
    2634             :         }
    2635             : 
    2636       29436 :         return lp_smbd_search_ask_sharemode(SNUM(fsp->conn));
    2637             : }
    2638             : 
    2639      381465 : bool fsp_getinfo_ask_sharemode(struct files_struct *fsp)
    2640             : {
    2641      381465 :         if (!fsp_generic_ask_sharemode(fsp)) {
    2642        1558 :                 return false;
    2643             :         }
    2644             : 
    2645      379907 :         return lp_smbd_getinfo_ask_sharemode(SNUM(fsp->conn));
    2646             : }

Generated by: LCOV version 1.14