LCOV - code coverage report
Current view: top level - source3/smbd - files.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 629 879 71.6 %
Date: 2024-06-13 04:01:37 Functions: 46 51 90.2 %

          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             : 
      29             : #define FILE_HANDLE_OFFSET 0x1000
      30             : 
      31             : static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
      32             :                                      struct smb_filename **_smb_fname);
      33             : 
      34             : /**
      35             :  * create new fsp to be used for file_new or a durable handle reconnect
      36             :  */
      37      146114 : NTSTATUS fsp_new(struct connection_struct *conn, TALLOC_CTX *mem_ctx,
      38             :                  files_struct **result)
      39             : {
      40      146114 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
      41      146114 :         files_struct *fsp = NULL;
      42      146114 :         struct smbd_server_connection *sconn = conn->sconn;
      43             : 
      44      146114 :         fsp = talloc_zero(mem_ctx, struct files_struct);
      45      146114 :         if (fsp == NULL) {
      46           0 :                 goto fail;
      47             :         }
      48             : 
      49             :         /*
      50             :          * This can't be a child of fsp because the file_handle can be ref'd
      51             :          * when doing a dos/fcb open, which will then share the file_handle
      52             :          * across multiple fsps.
      53             :          */
      54      146114 :         fsp->fh = fd_handle_create(mem_ctx);
      55      146114 :         if (fsp->fh == NULL) {
      56           0 :                 goto fail;
      57             :         }
      58             : 
      59      146114 :         fsp->fsp_flags.use_ofd_locks = !lp_smbd_force_process_locks(SNUM(conn));
      60             : #ifndef HAVE_OFD_LOCKS
      61             :         fsp->fsp_flags.use_ofd_locks = false;
      62             : #endif
      63             : 
      64      146114 :         fh_set_refcount(fsp->fh, 1);
      65      146114 :         fsp_set_fd(fsp, -1);
      66             : 
      67      146114 :         fsp->fnum = FNUM_FIELD_INVALID;
      68      146114 :         fsp->conn = conn;
      69      146114 :         fsp->close_write_time = make_omit_timespec();
      70             : 
      71      146114 :         DLIST_ADD(sconn->files, fsp);
      72      146114 :         sconn->num_files += 1;
      73             : 
      74      146114 :         conn->num_files_open++;
      75             : 
      76      146114 :         DBG_INFO("allocated files structure (%u used)\n",
      77             :                 (unsigned int)sconn->num_files);
      78             : 
      79      146114 :         *result = fsp;
      80      146114 :         return NT_STATUS_OK;
      81             : 
      82           0 : fail:
      83           0 :         if (fsp != NULL) {
      84           0 :                 TALLOC_FREE(fsp->fh);
      85             :         }
      86           0 :         TALLOC_FREE(fsp);
      87             : 
      88           0 :         return status;
      89             : }
      90             : 
      91      122645 : void fsp_set_gen_id(files_struct *fsp)
      92             : {
      93             :         static uint64_t gen_id = 1;
      94             : 
      95             :         /*
      96             :          * A billion of 64-bit increments per second gives us
      97             :          * more than 500 years of runtime without wrap.
      98             :          */
      99      122645 :         gen_id++;
     100      122645 :         fh_set_gen_id(fsp->fh, gen_id);
     101      122645 : }
     102             : 
     103             : /****************************************************************************
     104             :  Find first available file slot.
     105             : ****************************************************************************/
     106             : 
     107       20603 : NTSTATUS fsp_bind_smb(struct files_struct *fsp, struct smb_request *req)
     108             : {
     109       20603 :         struct smbXsrv_open *op = NULL;
     110             :         NTTIME now;
     111             :         NTSTATUS status;
     112             : 
     113       20603 :         if (req == NULL) {
     114        4264 :                 DBG_DEBUG("INTERNAL_OPEN_ONLY, skipping smbXsrv_open\n");
     115        4264 :                 return NT_STATUS_OK;
     116             :         }
     117             : 
     118       16339 :         now = timeval_to_nttime(&fsp->open_time);
     119             : 
     120       16339 :         status = smbXsrv_open_create(req->xconn,
     121       16339 :                                      fsp->conn->session_info,
     122             :                                      now,
     123             :                                      &op);
     124       16339 :         if (!NT_STATUS_IS_OK(status)) {
     125           0 :                 return status;
     126             :         }
     127       16339 :         fsp->op = op;
     128       16339 :         op->compat = fsp;
     129       16339 :         fsp->fnum = op->local_id;
     130             : 
     131       16339 :         fsp->mid = req->mid;
     132       16339 :         req->chain_fsp = fsp;
     133             : 
     134       16339 :         DBG_DEBUG("fsp [%s] mid [%" PRIu64"]\n",
     135             :                 fsp_str_dbg(fsp), fsp->mid);
     136             : 
     137       16339 :         return NT_STATUS_OK;
     138             : }
     139             : 
     140        9445 : NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
     141             :                   files_struct **result)
     142             : {
     143        9445 :         struct smbd_server_connection *sconn = conn->sconn;
     144             :         files_struct *fsp;
     145             :         NTSTATUS status;
     146             : 
     147        9445 :         status = fsp_new(conn, conn, &fsp);
     148        9445 :         if (!NT_STATUS_IS_OK(status)) {
     149           0 :                 return status;
     150             :         }
     151             : 
     152        9445 :         GetTimeOfDay(&fsp->open_time);
     153             : 
     154        9445 :         status = fsp_bind_smb(fsp, req);
     155        9445 :         if (!NT_STATUS_IS_OK(status)) {
     156           0 :                 file_free(NULL, fsp);
     157           0 :                 return status;
     158             :         }
     159             : 
     160        9445 :         fsp_set_gen_id(fsp);
     161             : 
     162             :         /*
     163             :          * Create an smb_filename with "" for the base_name.  There are very
     164             :          * few NULL checks, so make sure it's initialized with something. to
     165             :          * be safe until an audit can be done.
     166             :          */
     167        9445 :         fsp->fsp_name = synthetic_smb_fname(fsp,
     168             :                                             "",
     169             :                                             NULL,
     170             :                                             NULL,
     171             :                                             0,
     172             :                                             0);
     173        9445 :         if (fsp->fsp_name == NULL) {
     174           0 :                 file_free(NULL, fsp);
     175           0 :                 return NT_STATUS_NO_MEMORY;
     176             :         }
     177             : 
     178        9445 :         DBG_INFO("new file %s\n", fsp_fnum_dbg(fsp));
     179             : 
     180             :         /* A new fsp invalidates the positive and
     181             :           negative fsp_fi_cache as the new fsp is pushed
     182             :           at the start of the list and we search from
     183             :           a cache hit to the *end* of the list. */
     184             : 
     185        9445 :         ZERO_STRUCT(sconn->fsp_fi_cache);
     186             : 
     187        9445 :         *result = fsp;
     188        9445 :         return NT_STATUS_OK;
     189             : }
     190             : 
     191        4184 : NTSTATUS create_internal_fsp(connection_struct *conn,
     192             :                              const struct smb_filename *smb_fname,
     193             :                              struct files_struct **_fsp)
     194             : {
     195        4184 :         struct files_struct *fsp = NULL;
     196             :         NTSTATUS status;
     197             : 
     198        4184 :         status = file_new(NULL, conn, &fsp);
     199        4184 :         if (!NT_STATUS_IS_OK(status)) {
     200           0 :                 return status;
     201             :         }
     202             : 
     203        4184 :         status = fsp_set_smb_fname(fsp, smb_fname);
     204        4184 :         if (!NT_STATUS_IS_OK(status)) {
     205           0 :                 file_free(NULL, fsp);
     206           0 :                 return status;
     207             :         }
     208             : 
     209        4184 :         *_fsp = fsp;
     210        4184 :         return NT_STATUS_OK;
     211             : }
     212             : 
     213             : /*
     214             :  * Create an internal fsp for an *existing* directory.
     215             :  *
     216             :  * This should only be used by callers in the VFS that need to control the
     217             :  * opening of the directory. Otherwise use open_internal_dirfsp_at().
     218             :  */
     219        4184 : NTSTATUS create_internal_dirfsp(connection_struct *conn,
     220             :                                 const struct smb_filename *smb_dname,
     221             :                                 struct files_struct **_fsp)
     222             : {
     223        4184 :         struct files_struct *fsp = NULL;
     224             :         NTSTATUS status;
     225             : 
     226        4184 :         status = create_internal_fsp(conn, smb_dname, &fsp);
     227        4184 :         if (!NT_STATUS_IS_OK(status)) {
     228           0 :                 return status;
     229             :         }
     230             : 
     231        4184 :         fsp->access_mask = FILE_LIST_DIRECTORY;
     232        4184 :         fsp->fsp_flags.is_directory = true;
     233        4184 :         fsp->fsp_flags.is_dirfsp = true;
     234             : 
     235        4184 :         *_fsp = fsp;
     236        4184 :         return NT_STATUS_OK;
     237             : }
     238             : 
     239             : /*
     240             :  * Open an internal fsp for an *existing* directory.
     241             :  */
     242         846 : NTSTATUS open_internal_dirfsp(connection_struct *conn,
     243             :                               const struct smb_filename *smb_dname,
     244             :                               int _open_flags,
     245             :                               struct files_struct **_fsp)
     246             : {
     247         846 :         struct vfs_open_how how = { .flags = _open_flags, };
     248         846 :         struct files_struct *fsp = NULL;
     249             :         NTSTATUS status;
     250             : 
     251         846 :         status = create_internal_dirfsp(conn, smb_dname, &fsp);
     252         846 :         if (!NT_STATUS_IS_OK(status)) {
     253           0 :                 return status;
     254             :         }
     255             : 
     256             : #ifdef O_DIRECTORY
     257         846 :         how.flags |= O_DIRECTORY;
     258             : #endif
     259         846 :         status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, &how);
     260         846 :         if (!NT_STATUS_IS_OK(status)) {
     261           0 :                 DBG_INFO("Could not open fd for %s (%s)\n",
     262             :                          smb_fname_str_dbg(smb_dname),
     263             :                          nt_errstr(status));
     264           0 :                 file_free(NULL, fsp);
     265           0 :                 return status;
     266             :         }
     267             : 
     268         846 :         status = vfs_stat_fsp(fsp);
     269         846 :         if (!NT_STATUS_IS_OK(status)) {
     270           0 :                 file_free(NULL, fsp);
     271           0 :                 return status;
     272             :         }
     273             : 
     274         846 :         if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
     275           0 :                 DBG_ERR("%s is not a directory!\n",
     276             :                         smb_fname_str_dbg(smb_dname));
     277           0 :                 file_free(NULL, fsp);
     278           0 :                 return NT_STATUS_NOT_A_DIRECTORY;
     279             :         }
     280             : 
     281         846 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     282             : 
     283         846 :         *_fsp = fsp;
     284         846 :         return NT_STATUS_OK;
     285             : }
     286             : 
     287             : /*
     288             :  * Convert a pathref dirfsp into a real fsp. No need to do any cwd
     289             :  * tricks, we just open ".".
     290             :  */
     291        3338 : NTSTATUS openat_internal_dir_from_pathref(
     292             :         struct files_struct *dirfsp,
     293             :         int _open_flags,
     294             :         struct files_struct **_fsp)
     295             : {
     296        3338 :         struct connection_struct *conn = dirfsp->conn;
     297        3338 :         struct smb_filename *smb_dname = dirfsp->fsp_name;
     298        3338 :         struct files_struct *fsp = NULL;
     299        3338 :         char dot[] = ".";
     300        8668 :         struct smb_filename smb_dot = {
     301             :                 .base_name = dot,
     302        3338 :                 .flags = smb_dname->flags,
     303        3338 :                 .twrp = smb_dname->twrp,
     304             :         };
     305        3338 :         struct vfs_open_how how = { .flags = _open_flags, };
     306             :         NTSTATUS status;
     307             : 
     308        3338 :         status = create_internal_dirfsp(conn, smb_dname, &fsp);
     309        3338 :         if (!NT_STATUS_IS_OK(status)) {
     310           0 :                 return status;
     311             :         }
     312             : 
     313             :         /*
     314             :          * Pointless for opening ".", but you never know...
     315             :          */
     316        3338 :         how.flags |= O_NOFOLLOW;
     317             : 
     318        3338 :         status = fd_openat(dirfsp, &smb_dot, fsp, &how);
     319        3338 :         if (!NT_STATUS_IS_OK(status)) {
     320           0 :                 DBG_INFO("fd_openat(\"%s\", \".\") failed: %s\n",
     321             :                          fsp_str_dbg(dirfsp),
     322             :                          nt_errstr(status));
     323           0 :                 file_free(NULL, fsp);
     324           0 :                 return status;
     325             :         }
     326             : 
     327        3338 :         fsp->fsp_name->st = smb_dname->st;
     328        3338 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     329        3338 :         *_fsp = fsp;
     330        3338 :         return NT_STATUS_OK;
     331             : }
     332             : 
     333             : /*
     334             :  * The "link" in the name doesn't imply link in the filesystem
     335             :  * sense. It's a object that "links" together an fsp and an smb_fname
     336             :  * and the link allocated as talloc child of an fsp.
     337             :  *
     338             :  * The link is created for fsps that openat_pathref_fsp() returns in
     339             :  * smb_fname->fsp. When this fsp is freed by file_free() by some caller
     340             :  * somewhere, the destructor fsp_smb_fname_link_destructor() on the link object
     341             :  * will use the link to reset the reference in smb_fname->fsp that is about to
     342             :  * go away.
     343             :  *
     344             :  * This prevents smb_fname_internal_fsp_destructor() from seeing dangling fsp
     345             :  * pointers.
     346             :  */
     347             : 
     348             : struct fsp_smb_fname_link {
     349             :         struct fsp_smb_fname_link **smb_fname_link;
     350             :         struct files_struct **smb_fname_fsp;
     351             : };
     352             : 
     353      129169 : static int fsp_smb_fname_link_destructor(struct fsp_smb_fname_link *link)
     354             : {
     355      129169 :         if (link->smb_fname_link == NULL) {
     356           0 :                 return 0;
     357             :         }
     358             : 
     359      129169 :         *link->smb_fname_link = NULL;
     360      129169 :         *link->smb_fname_fsp = NULL;
     361      129169 :         return 0;
     362             : }
     363             : 
     364      259190 : static NTSTATUS fsp_smb_fname_link(struct files_struct *fsp,
     365             :                                    struct fsp_smb_fname_link **smb_fname_link,
     366             :                                    struct files_struct **smb_fname_fsp)
     367             : {
     368      259190 :         struct fsp_smb_fname_link *link = NULL;
     369             : 
     370      259190 :         SMB_ASSERT(*smb_fname_link == NULL);
     371      259190 :         SMB_ASSERT(*smb_fname_fsp == NULL);
     372             : 
     373      259190 :         link = talloc_zero(fsp, struct fsp_smb_fname_link);
     374      259190 :         if (link == NULL) {
     375           0 :                 return NT_STATUS_NO_MEMORY;
     376             :         }
     377             : 
     378      259190 :         link->smb_fname_link = smb_fname_link;
     379      259190 :         link->smb_fname_fsp = smb_fname_fsp;
     380      259190 :         *smb_fname_link = link;
     381      259190 :         *smb_fname_fsp = fsp;
     382             : 
     383      259190 :         talloc_set_destructor(link, fsp_smb_fname_link_destructor);
     384      259190 :         return NT_STATUS_OK;
     385             : }
     386             : 
     387             : /*
     388             :  * Free a link, carefully avoiding to trigger the link destructor
     389             :  */
     390      153216 : static void destroy_fsp_smb_fname_link(struct fsp_smb_fname_link **_link)
     391             : {
     392      153216 :         struct fsp_smb_fname_link *link = *_link;
     393             : 
     394      153216 :         if (link == NULL) {
     395       23195 :                 return;
     396             :         }
     397      130021 :         talloc_set_destructor(link, NULL);
     398      130021 :         TALLOC_FREE(link);
     399      130021 :         *_link = NULL;
     400             : }
     401             : 
     402             : /*
     403             :  * Talloc destructor set on an smb_fname set by openat_pathref_fsp() used to
     404             :  * close the embedded smb_fname->fsp.
     405             :  */
     406       95166 : static int smb_fname_fsp_destructor(struct smb_filename *smb_fname)
     407             : {
     408       95166 :         struct files_struct *fsp = smb_fname->fsp;
     409             :         NTSTATUS status;
     410       95166 :         int saved_errno = errno;
     411             : 
     412       95166 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
     413             : 
     414       95166 :         if (fsp == NULL) {
     415           2 :                 errno = saved_errno;
     416           2 :                 return 0;
     417             :         }
     418             : 
     419       95164 :         if (fsp_is_alternate_stream(fsp)) {
     420          16 :                 struct files_struct *tmp_base_fsp = fsp->base_fsp;
     421             : 
     422          16 :                 fsp_set_base_fsp(fsp, NULL);
     423             : 
     424          16 :                 status = fd_close(tmp_base_fsp);
     425          16 :                 if (!NT_STATUS_IS_OK(status)) {
     426           0 :                         DBG_ERR("Closing fd for fsp [%s] failed: %s. "
     427             :                                 "Please check your filesystem!!!\n",
     428             :                                 fsp_str_dbg(fsp), nt_errstr(status));
     429             :                 }
     430          16 :                 file_free(NULL, tmp_base_fsp);
     431             :         }
     432             : 
     433       95164 :         status = fd_close(fsp);
     434       95164 :         if (!NT_STATUS_IS_OK(status)) {
     435           0 :                 DBG_ERR("Closing fd for fsp [%s] failed: %s. "
     436             :                         "Please check your filesystem!!!\n",
     437             :                         fsp_str_dbg(fsp), nt_errstr(status));
     438             :         }
     439       95164 :         file_free(NULL, fsp);
     440       95164 :         smb_fname->fsp = NULL;
     441             : 
     442       95164 :         errno = saved_errno;
     443       95164 :         return 0;
     444             : }
     445             : 
     446      113200 : static NTSTATUS openat_pathref_fullname(
     447             :         struct connection_struct *conn,
     448             :         const struct files_struct *dirfsp,
     449             :         struct files_struct *basefsp,
     450             :         struct smb_filename **full_fname,
     451             :         struct smb_filename *smb_fname,
     452             :         const struct vfs_open_how *how)
     453             : {
     454      113200 :         struct files_struct *fsp = NULL;
     455      113200 :         bool have_dirfsp = (dirfsp != NULL);
     456      113200 :         bool have_basefsp = (basefsp != NULL);
     457             :         NTSTATUS status;
     458             : 
     459      113200 :         DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
     460             : 
     461      113200 :         SMB_ASSERT(smb_fname->fsp == NULL);
     462      113200 :         SMB_ASSERT(have_dirfsp != have_basefsp);
     463             : 
     464      113200 :         status = fsp_new(conn, conn, &fsp);
     465      113200 :         if (!NT_STATUS_IS_OK(status)) {
     466           0 :                 return status;
     467             :         }
     468             : 
     469      113200 :         GetTimeOfDay(&fsp->open_time);
     470      113200 :         fsp_set_gen_id(fsp);
     471      113200 :         ZERO_STRUCT(conn->sconn->fsp_fi_cache);
     472             : 
     473      113200 :         fsp->fsp_flags.is_pathref = true;
     474             : 
     475      113200 :         status = fsp_attach_smb_fname(fsp, full_fname);
     476      113200 :         if (!NT_STATUS_IS_OK(status)) {
     477           0 :                 goto fail;
     478             :         }
     479      113200 :         fsp_set_base_fsp(fsp, basefsp);
     480             : 
     481      113200 :         status = fd_openat(dirfsp, smb_fname, fsp, how);
     482      113200 :         if (!NT_STATUS_IS_OK(status)) {
     483             : 
     484       13326 :                 smb_fname->st = fsp->fsp_name->st;
     485             : 
     486       21752 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ||
     487       21748 :                     NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
     488       13322 :                     NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK))
     489             :                 {
     490             :                         /*
     491             :                          * streams_xattr return NT_STATUS_NOT_FOUND for
     492             :                          * opens of not yet existing streams.
     493             :                          *
     494             :                          * ELOOP maps to NT_STATUS_OBJECT_PATH_NOT_FOUND
     495             :                          * and this will result from a open request from
     496             :                          * a POSIX client on a symlink.
     497             :                          *
     498             :                          * NT_STATUS_OBJECT_NAME_NOT_FOUND is the simple
     499             :                          * ENOENT case.
     500             :                          *
     501             :                          * NT_STATUS_STOPPED_ON_SYMLINK is returned when trying
     502             :                          * to open a symlink, our callers are not interested in
     503             :                          * this.
     504             :                          */
     505          20 :                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
     506             :                 }
     507       13326 :                 goto fail;
     508             :         }
     509             : 
     510             :         /*
     511             :          * fd_openat() has done an FSTAT on the handle
     512             :          * so update the smb_fname stat info with "truth".
     513             :          * from the handle.
     514             :          */
     515       99874 :         smb_fname->st = fsp->fsp_name->st;
     516             : 
     517       99874 :         fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
     518             : 
     519       99874 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     520             : 
     521       99874 :         status = fsp_smb_fname_link(fsp,
     522             :                                     &smb_fname->fsp_link,
     523             :                                     &smb_fname->fsp);
     524       99874 :         if (!NT_STATUS_IS_OK(status)) {
     525           0 :                 goto fail;
     526             :         }
     527             : 
     528       99874 :         DBG_DEBUG("fsp [%s]: OK\n", fsp_str_dbg(fsp));
     529             : 
     530       99874 :         talloc_set_destructor(smb_fname, smb_fname_fsp_destructor);
     531       99874 :         return NT_STATUS_OK;
     532             : 
     533       13326 : fail:
     534       13326 :         DBG_DEBUG("Opening pathref for [%s] failed: %s\n",
     535             :                   smb_fname_str_dbg(smb_fname),
     536             :                   nt_errstr(status));
     537             : 
     538       13326 :         fsp_set_base_fsp(fsp, NULL);
     539       13326 :         fd_close(fsp);
     540       13326 :         file_free(NULL, fsp);
     541       13326 :         return status;
     542             : }
     543             : 
     544             : /*
     545             :  * Open an internal O_PATH based fsp for smb_fname. If O_PATH is not
     546             :  * available, open O_RDONLY as root. Both is done in fd_open() ->
     547             :  * non_widelink_open(), triggered by setting fsp->fsp_flags.is_pathref to
     548             :  * true.
     549             :  */
     550      113128 : NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
     551             :                             struct smb_filename *smb_fname)
     552             : {
     553      113128 :         connection_struct *conn = dirfsp->conn;
     554      113128 :         struct smb_filename *full_fname = NULL;
     555      113128 :         struct smb_filename *base_fname = NULL;
     556      113128 :         struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
     557             :         NTSTATUS status;
     558             : 
     559      113128 :         DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
     560             : 
     561      113128 :         if (smb_fname->fsp != NULL) {
     562             :                 /* We already have one for this name. */
     563           0 :                 DBG_DEBUG("smb_fname [%s] already has a pathref fsp.\n",
     564             :                         smb_fname_str_dbg(smb_fname));
     565           0 :                 return NT_STATUS_OK;
     566             :         }
     567             : 
     568      113144 :         if (is_named_stream(smb_fname) &&
     569          32 :             ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
     570           0 :                 DBG_DEBUG("stream open [%s] on non-stream share\n",
     571             :                           smb_fname_str_dbg(smb_fname));
     572           0 :                 return NT_STATUS_OBJECT_NAME_INVALID;
     573             :         }
     574             : 
     575      113128 :         if (!is_named_stream(smb_fname)) {
     576             :                 /*
     577             :                  * openat_pathref_fullname() will make "full_fname" a
     578             :                  * talloc child of the smb_fname->fsp. Don't use
     579             :                  * talloc_tos() to allocate it to avoid making the
     580             :                  * talloc stackframe pool long-lived.
     581             :                  */
     582      113096 :                 full_fname = full_path_from_dirfsp_atname(
     583             :                         conn,
     584             :                         dirfsp,
     585             :                         smb_fname);
     586      113096 :                 if (full_fname == NULL) {
     587           0 :                         status = NT_STATUS_NO_MEMORY;
     588           0 :                         goto fail;
     589             :                 }
     590      113096 :                 status = openat_pathref_fullname(
     591             :                         conn, dirfsp, NULL, &full_fname, smb_fname, &how);
     592      113096 :                 TALLOC_FREE(full_fname);
     593      113096 :                 return status;
     594             :         }
     595             : 
     596             :         /*
     597             :          * stream open
     598             :          */
     599          32 :         base_fname = cp_smb_filename_nostream(conn, smb_fname);
     600          32 :         if (base_fname == NULL) {
     601           0 :                 return NT_STATUS_NO_MEMORY;
     602             :         }
     603             : 
     604          32 :         full_fname = full_path_from_dirfsp_atname(
     605             :                 conn,   /* no talloc_tos(), see comment above */
     606             :                 dirfsp,
     607             :                 base_fname);
     608          32 :         if (full_fname == NULL) {
     609           0 :                 status = NT_STATUS_NO_MEMORY;
     610           0 :                 goto fail;
     611             :         }
     612             : 
     613          32 :         status = openat_pathref_fullname(
     614             :                 conn, dirfsp, NULL, &full_fname, base_fname, &how);
     615          32 :         TALLOC_FREE(full_fname);
     616          32 :         if (!NT_STATUS_IS_OK(status)) {
     617           0 :                 DBG_DEBUG("openat_pathref_nostream failed: %s\n",
     618             :                           nt_errstr(status));
     619           0 :                 goto fail;
     620             :         }
     621             : 
     622          32 :         status = open_stream_pathref_fsp(&base_fname->fsp, smb_fname);
     623          32 :         if (!NT_STATUS_IS_OK(status)) {
     624           0 :                 DBG_DEBUG("open_stream_pathref_fsp failed: %s\n",
     625             :                           nt_errstr(status));
     626           0 :                 goto fail;
     627             :         }
     628             : 
     629          32 :         smb_fname_fsp_unlink(base_fname);
     630          32 : fail:
     631          32 :         TALLOC_FREE(base_fname);
     632          32 :         return status;
     633             : }
     634             : 
     635             : /*
     636             :  * Open a stream given an already opened base_fsp. Avoid
     637             :  * non_widelink_open: This is only valid for the case where we have a
     638             :  * valid non-cwd_fsp dirfsp that we can pass to SMB_VFS_OPENAT()
     639             :  */
     640          72 : NTSTATUS open_stream_pathref_fsp(
     641             :         struct files_struct **_base_fsp,
     642             :         struct smb_filename *smb_fname)
     643             : {
     644          72 :         struct files_struct *base_fsp = *_base_fsp;
     645          72 :         connection_struct *conn = base_fsp->conn;
     646          72 :         struct smb_filename *base_fname = base_fsp->fsp_name;
     647          72 :         struct smb_filename *full_fname = NULL;
     648          72 :         struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
     649             :         NTSTATUS status;
     650             : 
     651          72 :         SMB_ASSERT(smb_fname->fsp == NULL);
     652          72 :         SMB_ASSERT(is_named_stream(smb_fname));
     653             : 
     654         144 :         full_fname = synthetic_smb_fname(
     655             :                 conn, /* no talloc_tos(), this will be long-lived */
     656          72 :                 base_fname->base_name,
     657          72 :                 smb_fname->stream_name,
     658          72 :                 &smb_fname->st,
     659             :                 smb_fname->twrp,
     660             :                 smb_fname->flags);
     661          72 :         if (full_fname == NULL) {
     662           0 :                 return NT_STATUS_NO_MEMORY;
     663             :         }
     664             : 
     665          72 :         status = openat_pathref_fullname(
     666             :                 conn, NULL, base_fsp, &full_fname, smb_fname, &how);
     667          72 :         TALLOC_FREE(full_fname);
     668          72 :         return status;
     669             : }
     670             : 
     671       19443 : static char *path_to_strv(TALLOC_CTX *mem_ctx, const char *path)
     672             : {
     673       19443 :         char *result = talloc_strdup(mem_ctx, path);
     674             : 
     675       19443 :         if (result == NULL) {
     676           0 :                 return NULL;
     677             :         }
     678       19443 :         string_replace(result, '/', '\0');
     679       19443 :         return result;
     680             : }
     681             : 
     682       12870 : static NTSTATUS readlink_talloc(
     683             :         TALLOC_CTX *mem_ctx,
     684             :         struct files_struct *dirfsp,
     685             :         struct smb_filename *smb_relname,
     686             :         char **_substitute)
     687             : {
     688             :         char buf[4096];
     689             :         ssize_t ret;
     690             :         char *substitute;
     691             :         NTSTATUS status;
     692             : 
     693       12870 :         if (_substitute == NULL) {
     694           0 :                 return NT_STATUS_OK;
     695             :         }
     696             : 
     697       12870 :         if (smb_relname == NULL) {
     698             :                 /*
     699             :                  * We have a Linux O_PATH handle in dirfsp and want to
     700             :                  * read its value, essentially a freadlink
     701             :                  */
     702           0 :                 smb_relname = synthetic_smb_fname(
     703             :                         talloc_tos(), "", NULL, NULL, 0, 0);
     704           0 :                 if (smb_relname == NULL) {
     705           0 :                         DBG_DEBUG("synthetic_smb_fname() failed\n");
     706           0 :                         return NT_STATUS_NO_MEMORY;
     707             :                 }
     708             :         }
     709             : 
     710       12870 :         ret = SMB_VFS_READLINKAT(
     711             :                 dirfsp->conn, dirfsp, smb_relname, buf, sizeof(buf));
     712       12870 :         if (ret < 0) {
     713           0 :                 status = map_nt_error_from_unix(errno);
     714           0 :                 DBG_DEBUG("SMB_VFS_READLINKAT() failed: %s\n",
     715             :                           strerror(errno));
     716           0 :                 return status;
     717             :         }
     718             : 
     719       12870 :         if ((size_t)ret == sizeof(buf)) {
     720             :                 /*
     721             :                  * Do we need symlink targets >4k?
     722             :                  */
     723           0 :                 DBG_DEBUG("Got full %zu bytes from readlink, too long\n",
     724             :                           sizeof(buf));
     725           0 :                 return NT_STATUS_BUFFER_OVERFLOW;
     726             :         }
     727             : 
     728       12870 :         substitute = talloc_strndup(mem_ctx, buf, ret);
     729       12870 :         if (substitute == NULL) {
     730           0 :                 DBG_DEBUG("talloc_strndup() failed\n");
     731           0 :                 return NT_STATUS_NO_MEMORY;
     732             :         }
     733             : 
     734       12870 :         *_substitute = substitute;
     735       12870 :         return NT_STATUS_OK;
     736             : }
     737             : 
     738       19443 : NTSTATUS openat_pathref_dirfsp_nosymlink(
     739             :         TALLOC_CTX *mem_ctx,
     740             :         struct connection_struct *conn,
     741             :         const char *path_in,
     742             :         NTTIME twrp,
     743             :         struct smb_filename **_smb_fname,
     744             :         size_t *unparsed,
     745             :         char **substitute)
     746             : {
     747       19443 :         struct files_struct *dirfsp = conn->cwd_fsp;
     748       19443 :         struct smb_filename full_fname = {
     749             :                 .base_name = NULL,
     750             :                 .twrp = twrp,
     751             :         };
     752       19443 :         struct smb_filename rel_fname = {
     753             :                 .base_name = NULL,
     754             :                 .twrp = twrp,
     755             :         };
     756       19443 :         struct smb_filename *result = NULL;
     757       19443 :         struct files_struct *fsp = NULL;
     758       19443 :         char *path = NULL, *next = NULL;
     759             :         int fd;
     760             :         NTSTATUS status;
     761       19443 :         struct vfs_open_how how = {
     762             :                 .flags = O_NOFOLLOW|O_DIRECTORY,
     763             :                 .mode = 0,
     764             :         };
     765             : 
     766       19443 :         DBG_DEBUG("path_in=%s\n", path_in);
     767             : 
     768       19443 :         status = fsp_new(conn, conn, &fsp);
     769       19443 :         if (!NT_STATUS_IS_OK(status)) {
     770           0 :                 DBG_DEBUG("fsp_new() failed: %s\n", nt_errstr(status));
     771           0 :                 goto fail;
     772             :         }
     773       19443 :         fsp->fsp_name = &full_fname;
     774             : 
     775             : #ifdef O_PATH
     776             :         /*
     777             :          * Add O_PATH manually, doing this by setting
     778             :          * fsp->fsp_flags.is_pathref will make us become_root() in the
     779             :          * non-O_PATH case, which would cause a security problem.
     780             :          */
     781       19443 :         how.flags |= O_PATH;
     782             : #else
     783             : #ifdef O_SEARCH
     784             :         /*
     785             :          * O_SEARCH just checks for the "x" bit. We are traversing
     786             :          * directories, so we don't need the implicit O_RDONLY ("r"
     787             :          * permissions) but only the "x"-permissions requested by
     788             :          * O_SEARCH. We need either O_PATH or O_SEARCH to correctly
     789             :          * function, without either we will incorrectly require also
     790             :          * the "r" bit when traversing the directory hierarchy.
     791             :          */
     792             :         how.flags |= O_SEARCH;
     793             : #endif
     794             : #endif
     795             : 
     796       19443 :         full_fname.base_name = talloc_strdup(talloc_tos(), "");
     797       19443 :         if (full_fname.base_name == NULL) {
     798           0 :                 DBG_DEBUG("talloc_strdup() failed\n");
     799           0 :                 goto nomem;
     800             :         }
     801             : 
     802             :         /*
     803             :          * First split the path into individual components.
     804             :          */
     805       19443 :         path = path_to_strv(talloc_tos(), path_in);
     806       19443 :         if (path == NULL) {
     807           0 :                 DBG_DEBUG("path_to_strv() failed\n");
     808           0 :                 goto nomem;
     809             :         }
     810             : 
     811             :         /*
     812             :          * First we loop over all components
     813             :          * in order to verify, there's no '.' or '..'
     814             :          */
     815       19443 :         rel_fname.base_name = path;
     816      235843 :         while (rel_fname.base_name != NULL) {
     817             : 
     818      203667 :                 next = strv_next(path, rel_fname.base_name);
     819             : 
     820             :                 /*
     821             :                  * Path sanitizing further up has cleaned or rejected
     822             :                  * empty path components. Assert this here.
     823             :                  */
     824      203667 :                 SMB_ASSERT(rel_fname.base_name[0] != '\0');
     825             : 
     826      203667 :                 if (ISDOT(rel_fname.base_name) || ISDOTDOT(rel_fname.base_name)) {
     827           0 :                         DBG_DEBUG("%s contains a dot\n", path_in);
     828           0 :                         status = NT_STATUS_OBJECT_NAME_INVALID;
     829           0 :                         goto fail;
     830             :                 }
     831             : 
     832             :                 /* Check veto files. */
     833      203667 :                 if (IS_VETO_PATH(conn, rel_fname.base_name)) {
     834           0 :                         DBG_DEBUG("%s contains veto files path component %s\n",
     835             :                                   path_in, rel_fname.base_name);
     836           0 :                         status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
     837           0 :                         goto fail;
     838             :                 }
     839             : 
     840      203667 :                 rel_fname.base_name = next;
     841             :         }
     842             : 
     843       19443 :         if (conn->open_how_resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
     844             : 
     845             :                 /*
     846             :                  * Try a direct openat2 with RESOLVE_NO_SYMLINKS to
     847             :                  * avoid the openat/close loop further down.
     848             :                  */
     849             : 
     850       19386 :                 rel_fname.base_name = discard_const_p(char, path_in);
     851       19386 :                 how.resolve = VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
     852             : 
     853       19386 :                 fd = SMB_VFS_OPENAT(conn, dirfsp, &rel_fname, fsp, &how);
     854       19386 :                 if (fd >= 0) {
     855        5938 :                         fsp_set_fd(fsp, fd);
     856        5938 :                         TALLOC_FREE(full_fname.base_name);
     857        5938 :                         full_fname = rel_fname;
     858        5938 :                         goto done;
     859             :                 }
     860             : 
     861       13448 :                 status = map_nt_error_from_unix(errno);
     862       13448 :                 DBG_DEBUG("SMB_VFS_OPENAT(%s, %s, RESOLVE_NO_SYMLINKS) returned %d %s => %s\n",
     863             :                           smb_fname_str_dbg(dirfsp->fsp_name), path_in,
     864             :                           errno, strerror(errno), nt_errstr(status));
     865       13448 :                 SMB_ASSERT(fd == -1);
     866       13448 :                 switch (errno) {
     867           0 :                 case ENOSYS:
     868             :                         /*
     869             :                          * We got ENOSYS, so fallback to the old code
     870             :                          * if the kernel doesn't support openat2() yet.
     871             :                          */
     872           0 :                         break;
     873             : 
     874       12870 :                 case ELOOP:
     875             :                 case ENOTDIR:
     876             :                         /*
     877             :                          * For ELOOP we also fallback in order to
     878             :                          * return the correct information with
     879             :                          * NT_STATUS_STOPPED_ON_SYMLINK.
     880             :                          *
     881             :                          * O_NOFOLLOW|O_DIRECTORY results in
     882             :                          * ENOTDIR instead of ELOOP for the final
     883             :                          * component.
     884             :                          */
     885       12870 :                         break;
     886             : 
     887         578 :                 case ENOENT:
     888             :                         /*
     889             :                          * If we got ENOENT, the filesystem could
     890             :                          * be case sensitive. For now we only do
     891             :                          * the get_real_filename_at() dance in
     892             :                          * the fallback loop below.
     893             :                          */
     894         578 :                         break;
     895             : 
     896           0 :                 default:
     897           0 :                         goto fail;
     898             :                 }
     899             : 
     900             :                 /*
     901             :                  * Just fallback to the openat loop
     902             :                  */
     903       13448 :                 how.resolve = 0;
     904             :         }
     905             : 
     906             :         /*
     907             :          * Now we loop over all components
     908             :          * opening each one and using it
     909             :          * as dirfd for the next one.
     910             :          *
     911             :          * It means we can detect symlinks
     912             :          * within the path.
     913             :          */
     914       13505 :         rel_fname.base_name = path;
     915       19865 : next:
     916       19865 :         next = strv_next(path, rel_fname.base_name);
     917             : 
     918       19865 :         fd = SMB_VFS_OPENAT(
     919             :                 conn,
     920             :                 dirfsp,
     921             :                 &rel_fname,
     922             :                 fsp,
     923             :                 &how);
     924             : 
     925       19865 :         if ((fd == -1) && (errno == ENOENT)) {
     926         612 :                 const char *orig_base_name = rel_fname.base_name;
     927             : 
     928        1222 :                 status = get_real_filename_at(
     929             :                         dirfsp,
     930         612 :                         rel_fname.base_name,
     931             :                         talloc_tos(),
     932             :                         &rel_fname.base_name);
     933             : 
     934         612 :                 if (!NT_STATUS_IS_OK(status)) {
     935          51 :                         DBG_DEBUG("get_real_filename_at failed: %s\n",
     936             :                                   nt_errstr(status));
     937          51 :                         goto fail;
     938             :                 }
     939             : 
     940             :                 /* Name might have been demangled - check veto files. */
     941         561 :                 if (IS_VETO_PATH(conn, rel_fname.base_name)) {
     942           0 :                         DBG_DEBUG("%s contains veto files path component %s => %s\n",
     943             :                                   path_in, orig_base_name, rel_fname.base_name);
     944           0 :                         status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
     945           0 :                         goto fail;
     946             :                 }
     947             : 
     948         561 :                 fd = SMB_VFS_OPENAT(
     949             :                         conn,
     950             :                         dirfsp,
     951             :                         &rel_fname,
     952             :                         fsp,
     953             :                         &how);
     954             :         }
     955             : 
     956             :         /*
     957             :          * O_NOFOLLOW|O_DIRECTORY results in
     958             :          * ENOTDIR instead of ELOOP.
     959             :          *
     960             :          * But we should be prepared to handle ELOOP too.
     961             :          */
     962       19814 :         if ((fd == -1) && (errno == ENOTDIR || errno == ELOOP)) {
     963       12870 :                 NTSTATUS orig_status = map_nt_error_from_unix(errno);
     964             : 
     965       12870 :                 status = readlink_talloc(
     966             :                         mem_ctx, dirfsp, &rel_fname, substitute);
     967             : 
     968       12870 :                 if (NT_STATUS_IS_OK(status)) {
     969             :                         /*
     970             :                          * readlink_talloc() found a symlink
     971             :                          */
     972       12870 :                         status = NT_STATUS_STOPPED_ON_SYMLINK;
     973             : 
     974       12870 :                         if (unparsed != NULL) {
     975       12870 :                                 if (next == NULL) {
     976        1078 :                                         *unparsed = 0;
     977             :                                 } else {
     978       11792 :                                         size_t parsed = next - path;
     979       11792 :                                         size_t len = talloc_get_size(path);
     980       11792 :                                         *unparsed = len - parsed;
     981             :                                 }
     982             :                         }
     983             :                         /*
     984             :                          * If we're on an MSDFS share, see if this is
     985             :                          * an MSDFS link.
     986             :                          */
     987       25740 :                         if (lp_host_msdfs() &&
     988       22296 :                             lp_msdfs_root(SNUM(conn)) &&
     989        9426 :                             (substitute != NULL) &&
     990       18852 :                             strnequal(*substitute, "msdfs:", 6) &&
     991        9426 :                             is_msdfs_link(dirfsp, &rel_fname))
     992             :                         {
     993        9426 :                                 status = NT_STATUS_PATH_NOT_COVERED;
     994             :                         }
     995             :                 } else {
     996             : 
     997           0 :                         DBG_DEBUG("readlink_talloc failed: %s\n",
     998             :                                   nt_errstr(status));
     999             :                         /*
    1000             :                          * Restore the error status from SMB_VFS_OPENAT()
    1001             :                          */
    1002           0 :                         status = orig_status;
    1003             :                 }
    1004       12870 :                 goto fail;
    1005             :         }
    1006             : 
    1007        6944 :         if (fd == -1) {
    1008           0 :                 status = map_nt_error_from_unix(errno);
    1009           0 :                 DBG_DEBUG("SMB_VFS_OPENAT() failed: %s\n",
    1010             :                           strerror(errno));
    1011           0 :                 goto fail;
    1012             :         }
    1013        6944 :         fsp_set_fd(fsp, fd);
    1014             : 
    1015        6944 :         fsp->fsp_flags.is_directory = true; /* See O_DIRECTORY above */
    1016             : 
    1017       12162 :         full_fname.base_name = talloc_asprintf_append_buffer(
    1018             :                         full_fname.base_name,
    1019             :                         "%s%s",
    1020        6944 :                         full_fname.base_name[0] == '\0' ? "" : "/",
    1021             :                         rel_fname.base_name);
    1022             : 
    1023        6944 :         if (full_fname.base_name == NULL) {
    1024           0 :                 DBG_DEBUG("talloc_asprintf_append_buffer() failed\n");
    1025           0 :                 goto nomem;
    1026             :         }
    1027             : 
    1028        6944 :         if (next != NULL) {
    1029        6360 :                 struct files_struct *tmp = NULL;
    1030             : 
    1031        6360 :                 if (dirfsp != conn->cwd_fsp) {
    1032        2334 :                         fd_close(dirfsp);
    1033             :                 }
    1034             : 
    1035        6360 :                 tmp = dirfsp;
    1036        6360 :                 dirfsp = fsp;
    1037             : 
    1038        6360 :                 if (tmp == conn->cwd_fsp) {
    1039        4026 :                         status = fsp_new(conn, conn, &fsp);
    1040        4026 :                         if (!NT_STATUS_IS_OK(status)) {
    1041           0 :                                 DBG_DEBUG("fsp_new() failed: %s\n",
    1042             :                                           nt_errstr(status));
    1043           0 :                                 goto fail;
    1044             :                         }
    1045        4026 :                         fsp->fsp_name = &full_fname;
    1046             :                 } else {
    1047        2334 :                         fsp = tmp;
    1048             :                 }
    1049             : 
    1050        6360 :                 rel_fname.base_name = next;
    1051             : 
    1052        6360 :                 goto next;
    1053             :         }
    1054             : 
    1055         584 :         if (dirfsp != conn->cwd_fsp) {
    1056         531 :                 SMB_ASSERT(fsp_get_pathref_fd(dirfsp) != -1);
    1057         531 :                 fd_close(dirfsp);
    1058         531 :                 dirfsp->fsp_name = NULL;
    1059         531 :                 file_free(NULL, dirfsp);
    1060         531 :                 dirfsp = NULL;
    1061             :         }
    1062             : 
    1063        6294 : done:
    1064        6522 :         fsp->fsp_flags.is_pathref = true;
    1065        6522 :         fsp->fsp_name = NULL;
    1066             : 
    1067        6522 :         status = fsp_set_smb_fname(fsp, &full_fname);
    1068        6522 :         if (!NT_STATUS_IS_OK(status)) {
    1069           0 :                 DBG_DEBUG("fsp_set_smb_fname() failed: %s\n",
    1070             :                           nt_errstr(status));
    1071           0 :                 goto fail;
    1072             :         }
    1073             : 
    1074        6522 :         status = vfs_stat_fsp(fsp);
    1075        6522 :         if (!NT_STATUS_IS_OK(status)) {
    1076           0 :                 DBG_DEBUG("vfs_stat_fsp(%s) failed: %s\n",
    1077             :                           fsp_str_dbg(fsp),
    1078             :                           nt_errstr(status));
    1079           0 :                 goto fail;
    1080             :         }
    1081             :         /*
    1082             :          * We must correctly set fsp->file_id as code inside
    1083             :          * open.c will use this to check if delete_on_close
    1084             :          * has been set on the dirfsp.
    1085             :          */
    1086        6522 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
    1087             : 
    1088        6522 :         result = cp_smb_filename(mem_ctx, fsp->fsp_name);
    1089        6522 :         if (result == NULL) {
    1090           0 :                 DBG_DEBUG("cp_smb_filename() failed\n");
    1091           0 :                 goto nomem;
    1092             :         }
    1093             : 
    1094        6522 :         status = fsp_smb_fname_link(fsp,
    1095             :                                         &result->fsp_link,
    1096             :                                         &result->fsp);
    1097        6522 :         if (!NT_STATUS_IS_OK(status)) {
    1098           0 :                 goto fail;
    1099             :         }
    1100        6522 :         talloc_set_destructor(result, smb_fname_fsp_destructor);
    1101             : 
    1102        6522 :         *_smb_fname = result;
    1103             : 
    1104        6522 :         DBG_DEBUG("returning %s\n", smb_fname_str_dbg(result));
    1105             : 
    1106        6522 :         return NT_STATUS_OK;
    1107             : 
    1108           0 : nomem:
    1109           0 :         status = NT_STATUS_NO_MEMORY;
    1110       12921 : fail:
    1111       12921 :         if (fsp != NULL) {
    1112       12921 :                 if (fsp_get_pathref_fd(fsp) != -1) {
    1113           0 :                         fd_close(fsp);
    1114             :                 }
    1115       12921 :                 file_free(NULL, fsp);
    1116       12921 :                 fsp = NULL;
    1117             :         }
    1118             : 
    1119       12921 :         if ((dirfsp != NULL) && (dirfsp != conn->cwd_fsp)) {
    1120        3495 :                 SMB_ASSERT(fsp_get_pathref_fd(dirfsp) != -1);
    1121        3495 :                 fd_close(dirfsp);
    1122        3495 :                 dirfsp->fsp_name = NULL;
    1123        3495 :                 file_free(NULL, dirfsp);
    1124        3495 :                 dirfsp = NULL;
    1125             :         }
    1126             : 
    1127       12921 :         TALLOC_FREE(path);
    1128       12921 :         return status;
    1129             : }
    1130             : 
    1131       56674 : void smb_fname_fsp_unlink(struct smb_filename *smb_fname)
    1132             : {
    1133       56674 :         talloc_set_destructor(smb_fname, NULL);
    1134       56674 :         smb_fname->fsp = NULL;
    1135       56674 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
    1136       56674 : }
    1137             : 
    1138             : /*
    1139             :  * Move any existing embedded fsp refs from the src name to the
    1140             :  * destination. It's safe to call this on src smb_fname's that have no embedded
    1141             :  * pathref fsp.
    1142             :  */
    1143       22279 : NTSTATUS move_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,
    1144             :                                  struct smb_filename *smb_fname_src)
    1145             : {
    1146             :         NTSTATUS status;
    1147             : 
    1148             :         /*
    1149             :          * The target should always not be linked yet!
    1150             :          */
    1151       22279 :         SMB_ASSERT(smb_fname_dst->fsp == NULL);
    1152       22279 :         SMB_ASSERT(smb_fname_dst->fsp_link == NULL);
    1153             : 
    1154       22279 :         if (smb_fname_src->fsp == NULL) {
    1155          80 :                 return NT_STATUS_OK;
    1156             :         }
    1157             : 
    1158       22199 :         status = fsp_smb_fname_link(smb_fname_src->fsp,
    1159             :                                     &smb_fname_dst->fsp_link,
    1160             :                                     &smb_fname_dst->fsp);
    1161       22199 :         if (!NT_STATUS_IS_OK(status)) {
    1162           0 :                 return status;
    1163             :         }
    1164             : 
    1165       22199 :         talloc_set_destructor(smb_fname_dst, smb_fname_fsp_destructor);
    1166             : 
    1167       22199 :         smb_fname_fsp_unlink(smb_fname_src);
    1168             : 
    1169       22199 :         return NT_STATUS_OK;
    1170             : }
    1171             : 
    1172             : /**
    1173             :  * Create an smb_fname and open smb_fname->fsp pathref
    1174             :  **/
    1175       10473 : NTSTATUS synthetic_pathref(TALLOC_CTX *mem_ctx,
    1176             :                            struct files_struct *dirfsp,
    1177             :                            const char *base_name,
    1178             :                            const char *stream_name,
    1179             :                            const SMB_STRUCT_STAT *psbuf,
    1180             :                            NTTIME twrp,
    1181             :                            uint32_t flags,
    1182             :                            struct smb_filename **_smb_fname)
    1183             : {
    1184       10473 :         struct smb_filename *smb_fname = NULL;
    1185             :         NTSTATUS status;
    1186             : 
    1187       10473 :         smb_fname = synthetic_smb_fname(mem_ctx,
    1188             :                                         base_name,
    1189             :                                         stream_name,
    1190             :                                         psbuf,
    1191             :                                         twrp,
    1192             :                                         flags);
    1193       10473 :         if (smb_fname == NULL) {
    1194           0 :                 return NT_STATUS_NO_MEMORY;
    1195             :         }
    1196             : 
    1197       10473 :         status = openat_pathref_fsp(dirfsp, smb_fname);
    1198       10473 :         if (!NT_STATUS_IS_OK(status)) {
    1199         315 :                 DBG_NOTICE("opening [%s] failed\n",
    1200             :                         smb_fname_str_dbg(smb_fname));
    1201         315 :                 TALLOC_FREE(smb_fname);
    1202         315 :                 return status;
    1203             :         }
    1204             : 
    1205       10158 :         *_smb_fname = smb_fname;
    1206       10158 :         return NT_STATUS_OK;
    1207             : }
    1208             : 
    1209        1376 : static int atname_destructor(struct smb_filename *smb_fname)
    1210             : {
    1211        1376 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
    1212        1376 :         return 0;
    1213             : }
    1214             : 
    1215             : /**
    1216             :  * Turn a path into a parent pathref and atname
    1217             :  *
    1218             :  * This returns the parent pathref in _parent and the name relative to it. If
    1219             :  * smb_fname was a pathref (ie smb_fname->fsp != NULL), then _atname will be a
    1220             :  * pathref as well, ie _atname->fsp will point at the same fsp as
    1221             :  * smb_fname->fsp.
    1222             :  **/
    1223        1773 : NTSTATUS parent_pathref(TALLOC_CTX *mem_ctx,
    1224             :                         struct files_struct *dirfsp,
    1225             :                         const struct smb_filename *smb_fname,
    1226             :                         struct smb_filename **_parent,
    1227             :                         struct smb_filename **_atname)
    1228             : {
    1229        1773 :         struct smb_filename *parent = NULL;
    1230        1773 :         struct smb_filename *atname = NULL;
    1231             :         NTSTATUS status;
    1232             : 
    1233        1773 :         status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
    1234             :                                          mem_ctx,
    1235             :                                          smb_fname,
    1236             :                                          &parent,
    1237             :                                          &atname);
    1238        1773 :         if (!NT_STATUS_IS_OK(status)) {
    1239           0 :                 return status;
    1240             :         }
    1241             : 
    1242             :         /*
    1243             :          * We know that the parent name must
    1244             :          * exist, and the name has been canonicalized
    1245             :          * even if this was a POSIX pathname.
    1246             :          * Ensure that we follow symlinks for
    1247             :          * the parent. See the torture test
    1248             :          * POSIX-SYMLINK-PARENT for details.
    1249             :          */
    1250        1773 :         parent->flags &= ~SMB_FILENAME_POSIX_PATH;
    1251             : 
    1252        1773 :         status = openat_pathref_fsp(dirfsp, parent);
    1253        1773 :         if (!NT_STATUS_IS_OK(status)) {
    1254           0 :                 TALLOC_FREE(parent);
    1255           0 :                 return status;
    1256             :         }
    1257             : 
    1258        1773 :         if (smb_fname->fsp != NULL) {
    1259        2609 :                 status = fsp_smb_fname_link(smb_fname->fsp,
    1260        1376 :                                             &atname->fsp_link,
    1261        1376 :                                             &atname->fsp);
    1262        1376 :                 if (!NT_STATUS_IS_OK(status)) {
    1263           0 :                         TALLOC_FREE(parent);
    1264           0 :                         return status;
    1265             :                 }
    1266        1376 :                 talloc_set_destructor(atname, atname_destructor);
    1267             :         }
    1268        1773 :         *_parent = parent;
    1269        1773 :         *_atname = atname;
    1270        1773 :         return NT_STATUS_OK;
    1271             : }
    1272             : 
    1273         278 : static bool close_file_in_loop(struct files_struct *fsp,
    1274             :                                enum file_close_type close_type)
    1275             : {
    1276         278 :         if (fsp_is_alternate_stream(fsp)) {
    1277             :                 /*
    1278             :                  * This is a stream, it can't be a base
    1279             :                  */
    1280           0 :                 SMB_ASSERT(fsp->stream_fsp == NULL);
    1281           0 :                 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
    1282             : 
    1283             :                 /*
    1284             :                  * Remove the base<->stream link so that
    1285             :                  * close_file_free() does not close fsp->base_fsp as
    1286             :                  * well. This would destroy walking the linked list of
    1287             :                  * fsps.
    1288             :                  */
    1289           0 :                 fsp->base_fsp->stream_fsp = NULL;
    1290           0 :                 fsp->base_fsp = NULL;
    1291             : 
    1292           0 :                 close_file_free(NULL, &fsp, close_type);
    1293           0 :                 return NULL;
    1294             :         }
    1295             : 
    1296         278 :         if (fsp->stream_fsp != NULL) {
    1297             :                 /*
    1298             :                  * This is the base of a stream.
    1299             :                  */
    1300           0 :                 SMB_ASSERT(fsp->stream_fsp->base_fsp == fsp);
    1301             : 
    1302             :                 /*
    1303             :                  * Remove the base<->stream link. This will make fsp
    1304             :                  * look like a normal fsp for the next round.
    1305             :                  */
    1306           0 :                 fsp->stream_fsp->base_fsp = NULL;
    1307           0 :                 fsp->stream_fsp = NULL;
    1308             : 
    1309             :                 /*
    1310             :                  * Have us called back a second time. In the second
    1311             :                  * round, "fsp" now looks like a normal fsp.
    1312             :                  */
    1313           0 :                 return false;
    1314             :         }
    1315             : 
    1316         278 :         close_file_free(NULL, &fsp, close_type);
    1317         278 :         return true;
    1318             : }
    1319             : 
    1320             : /****************************************************************************
    1321             :  Close all open files for a connection.
    1322             : ****************************************************************************/
    1323             : 
    1324             : struct file_close_conn_state {
    1325             :         struct connection_struct *conn;
    1326             :         enum file_close_type close_type;
    1327             :         bool fsp_left_behind;
    1328             : };
    1329             : 
    1330           4 : static struct files_struct *file_close_conn_fn(
    1331             :         struct files_struct *fsp,
    1332             :         void *private_data)
    1333             : {
    1334           4 :         struct file_close_conn_state *state = private_data;
    1335             :         bool did_close;
    1336             : 
    1337           4 :         if (fsp->conn != state->conn) {
    1338           2 :                 return NULL;
    1339             :         }
    1340             : 
    1341           2 :         if (fsp->op != NULL && fsp->op->global->durable) {
    1342             :                 /*
    1343             :                  * A tree disconnect closes a durable handle
    1344             :                  */
    1345           0 :                 fsp->op->global->durable = false;
    1346             :         }
    1347             : 
    1348           2 :         did_close = close_file_in_loop(fsp, state->close_type);
    1349           2 :         if (!did_close) {
    1350           0 :                 state->fsp_left_behind = true;
    1351             :         }
    1352             : 
    1353           2 :         return NULL;
    1354             : }
    1355             : 
    1356        5623 : void file_close_conn(connection_struct *conn, enum file_close_type close_type)
    1357             : {
    1358        5623 :         struct file_close_conn_state state = { .conn = conn,
    1359             :                                                .close_type = close_type };
    1360             : 
    1361        5623 :         files_forall(conn->sconn, file_close_conn_fn, &state);
    1362             : 
    1363        5623 :         if (state.fsp_left_behind) {
    1364           0 :                 state.fsp_left_behind = false;
    1365           0 :                 files_forall(conn->sconn, file_close_conn_fn, &state);
    1366           0 :                 SMB_ASSERT(!state.fsp_left_behind);
    1367             :         }
    1368        5623 : }
    1369             : 
    1370             : /****************************************************************************
    1371             :  Initialise file structures.
    1372             : ****************************************************************************/
    1373             : 
    1374             : static int files_max_open_fds;
    1375             : 
    1376        5309 : bool file_init_global(void)
    1377             : {
    1378        5309 :         int request_max = lp_max_open_files();
    1379             :         int real_lim;
    1380             :         int real_max;
    1381             : 
    1382        5309 :         if (files_max_open_fds != 0) {
    1383        5270 :                 return true;
    1384             :         }
    1385             : 
    1386             :         /*
    1387             :          * Set the max_open files to be the requested
    1388             :          * max plus a fudgefactor to allow for the extra
    1389             :          * fd's we need such as log files etc...
    1390             :          */
    1391          39 :         real_lim = set_maxfiles(request_max + MAX_OPEN_FUDGEFACTOR);
    1392             : 
    1393          39 :         real_max = real_lim - MAX_OPEN_FUDGEFACTOR;
    1394             : 
    1395          39 :         if (real_max + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536) {
    1396           0 :                 real_max = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
    1397             :         }
    1398             : 
    1399          39 :         if (real_max != request_max) {
    1400           0 :                 DEBUG(1, ("file_init_global: Information only: requested %d "
    1401             :                           "open files, %d are available.\n",
    1402             :                           request_max, real_max));
    1403             :         }
    1404             : 
    1405          39 :         SMB_ASSERT(real_max > 100);
    1406             : 
    1407          39 :         files_max_open_fds = real_max;
    1408          39 :         return true;
    1409             : }
    1410             : 
    1411        5270 : bool file_init(struct smbd_server_connection *sconn)
    1412             : {
    1413             :         bool ok;
    1414             : 
    1415        5270 :         ok = file_init_global();
    1416        5270 :         if (!ok) {
    1417           0 :                 return false;
    1418             :         }
    1419             : 
    1420        5270 :         sconn->real_max_open_files = files_max_open_fds;
    1421             : 
    1422        5270 :         return true;
    1423             : }
    1424             : 
    1425             : /****************************************************************************
    1426             :  Close files open by a specified vuid.
    1427             : ****************************************************************************/
    1428             : 
    1429             : struct file_close_user_state {
    1430             :         uint64_t vuid;
    1431             :         bool fsp_left_behind;
    1432             : };
    1433             : 
    1434         280 : static struct files_struct *file_close_user_fn(
    1435             :         struct files_struct *fsp,
    1436             :         void *private_data)
    1437             : {
    1438         280 :         struct file_close_user_state *state = private_data;
    1439             :         bool did_close;
    1440             : 
    1441         280 :         if (fsp->vuid != state->vuid) {
    1442           4 :                 return NULL;
    1443             :         }
    1444             : 
    1445         276 :         did_close = close_file_in_loop(fsp, SHUTDOWN_CLOSE);
    1446         276 :         if (!did_close) {
    1447           0 :                 state->fsp_left_behind = true;
    1448             :         }
    1449             : 
    1450         276 :         return NULL;
    1451             : }
    1452             : 
    1453        4958 : void file_close_user(struct smbd_server_connection *sconn, uint64_t vuid)
    1454             : {
    1455        4958 :         struct file_close_user_state state = { .vuid = vuid };
    1456             : 
    1457        4958 :         files_forall(sconn, file_close_user_fn, &state);
    1458             : 
    1459        4958 :         if (state.fsp_left_behind) {
    1460           0 :                 state.fsp_left_behind = false;
    1461           0 :                 files_forall(sconn, file_close_user_fn, &state);
    1462           0 :                 SMB_ASSERT(!state.fsp_left_behind);
    1463             :         }
    1464        4958 : }
    1465             : 
    1466             : /*
    1467             :  * Walk the files table until "fn" returns non-NULL
    1468             :  */
    1469             : 
    1470       12000 : struct files_struct *files_forall(
    1471             :         struct smbd_server_connection *sconn,
    1472             :         struct files_struct *(*fn)(struct files_struct *fsp,
    1473             :                                    void *private_data),
    1474             :         void *private_data)
    1475             : {
    1476             :         struct files_struct *fsp, *next;
    1477             : 
    1478       13192 :         for (fsp = sconn->files; fsp; fsp = next) {
    1479             :                 struct files_struct *ret;
    1480        1244 :                 next = fsp->next;
    1481        1244 :                 ret = fn(fsp, private_data);
    1482        1244 :                 if (ret != NULL) {
    1483          52 :                         return ret;
    1484             :                 }
    1485             :         }
    1486       11948 :         return NULL;
    1487             : }
    1488             : 
    1489             : /****************************************************************************
    1490             :  Find a fsp given a file descriptor.
    1491             : ****************************************************************************/
    1492             : 
    1493           0 : files_struct *file_find_fd(struct smbd_server_connection *sconn, int fd)
    1494             : {
    1495           0 :         int count=0;
    1496             :         files_struct *fsp;
    1497             : 
    1498           0 :         for (fsp=sconn->files; fsp; fsp=fsp->next,count++) {
    1499           0 :                 if (fsp_get_pathref_fd(fsp) == fd) {
    1500           0 :                         if (count > 10) {
    1501           0 :                                 DLIST_PROMOTE(sconn->files, fsp);
    1502             :                         }
    1503           0 :                         return fsp;
    1504             :                 }
    1505             :         }
    1506             : 
    1507           0 :         return NULL;
    1508             : }
    1509             : 
    1510             : /****************************************************************************
    1511             :  Find a fsp given a device, inode and file_id.
    1512             : ****************************************************************************/
    1513             : 
    1514          20 : files_struct *file_find_dif(struct smbd_server_connection *sconn,
    1515             :                             struct file_id id, unsigned long gen_id)
    1516             : {
    1517          20 :         int count=0;
    1518             :         files_struct *fsp;
    1519             : 
    1520          20 :         if (gen_id == 0) {
    1521           0 :                 return NULL;
    1522             :         }
    1523             : 
    1524          66 :         for (fsp = sconn->files; fsp; fsp = fsp->next,count++) {
    1525             :                 /*
    1526             :                  * We can have a fsp->fh->fd == -1 here as it could be a stat
    1527             :                  * open.
    1528             :                  */
    1529          66 :                 if (!file_id_equal(&fsp->file_id, &id)) {
    1530          26 :                         continue;
    1531             :                 }
    1532          40 :                 if (!fsp->fsp_flags.is_fsa) {
    1533          20 :                         continue;
    1534             :                 }
    1535          20 :                 if (fh_get_gen_id(fsp->fh) != gen_id) {
    1536           0 :                         continue;
    1537             :                 }
    1538          20 :                 if (count > 10) {
    1539           0 :                         DLIST_PROMOTE(sconn->files, fsp);
    1540             :                 }
    1541             :                 /* Paranoia check. */
    1542          20 :                 if ((fsp_get_pathref_fd(fsp) == -1) &&
    1543           0 :                     (fsp->oplock_type != NO_OPLOCK &&
    1544           0 :                      fsp->oplock_type != LEASE_OPLOCK))
    1545             :                 {
    1546             :                         struct file_id_buf idbuf;
    1547             : 
    1548           0 :                         DBG_ERR("file %s file_id = "
    1549             :                                 "%s, gen = %u oplock_type = %u is a "
    1550             :                                 "stat open with oplock type !\n",
    1551             :                                 fsp_str_dbg(fsp),
    1552             :                                 file_id_str_buf(fsp->file_id, &idbuf),
    1553             :                                 (unsigned int)fh_get_gen_id(fsp->fh),
    1554             :                                 (unsigned int)fsp->oplock_type);
    1555           0 :                         smb_panic("file_find_dif");
    1556             :                 }
    1557          20 :                 return fsp;
    1558             :         }
    1559             : 
    1560           0 :         return NULL;
    1561             : }
    1562             : 
    1563             : /****************************************************************************
    1564             :  Find the first fsp given a device and inode.
    1565             :  We use a singleton cache here to speed up searching from getfilepathinfo
    1566             :  calls.
    1567             : ****************************************************************************/
    1568             : 
    1569          41 : files_struct *file_find_di_first(struct smbd_server_connection *sconn,
    1570             :                                  struct file_id id,
    1571             :                                  bool need_fsa)
    1572             : {
    1573             :         files_struct *fsp;
    1574             : 
    1575          41 :         if (file_id_equal(&sconn->fsp_fi_cache.id, &id)) {
    1576             :                 /* Positive or negative cache hit. */
    1577           0 :                 return sconn->fsp_fi_cache.fsp;
    1578             :         }
    1579             : 
    1580          41 :         sconn->fsp_fi_cache.id = id;
    1581             : 
    1582         128 :         for (fsp=sconn->files;fsp;fsp=fsp->next) {
    1583         107 :                 if (need_fsa && !fsp->fsp_flags.is_fsa) {
    1584          22 :                         continue;
    1585             :                 }
    1586          85 :                 if (file_id_equal(&fsp->file_id, &id)) {
    1587             :                         /* Setup positive cache. */
    1588          20 :                         sconn->fsp_fi_cache.fsp = fsp;
    1589          20 :                         return fsp;
    1590             :                 }
    1591             :         }
    1592             : 
    1593             :         /* Setup negative cache. */
    1594          21 :         sconn->fsp_fi_cache.fsp = NULL;
    1595          21 :         return NULL;
    1596             : }
    1597             : 
    1598             : /****************************************************************************
    1599             :  Find the next fsp having the same device and inode.
    1600             : ****************************************************************************/
    1601             : 
    1602          20 : files_struct *file_find_di_next(files_struct *start_fsp,
    1603             :                                 bool need_fsa)
    1604             : {
    1605             :         files_struct *fsp;
    1606             : 
    1607          20 :         for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
    1608           0 :                 if (need_fsa && !fsp->fsp_flags.is_fsa) {
    1609           0 :                         continue;
    1610             :                 }
    1611           0 :                 if (file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
    1612           0 :                         return fsp;
    1613             :                 }
    1614             :         }
    1615             : 
    1616          20 :         return NULL;
    1617             : }
    1618             : 
    1619           0 : struct files_struct *file_find_one_fsp_from_lease_key(
    1620             :         struct smbd_server_connection *sconn,
    1621             :         const struct smb2_lease_key *lease_key)
    1622             : {
    1623             :         struct files_struct *fsp;
    1624             : 
    1625           0 :         for (fsp = sconn->files; fsp; fsp=fsp->next) {
    1626           0 :                 if ((fsp->lease != NULL) &&
    1627           0 :                     (fsp->lease->lease.lease_key.data[0] ==
    1628           0 :                      lease_key->data[0]) &&
    1629           0 :                     (fsp->lease->lease.lease_key.data[1] ==
    1630           0 :                      lease_key->data[1])) {
    1631           0 :                         return fsp;
    1632             :                 }
    1633             :         }
    1634           0 :         return NULL;
    1635             : }
    1636             : 
    1637             : /****************************************************************************
    1638             :  Find any fsp open with a pathname below that of an already open path.
    1639             : ****************************************************************************/
    1640             : 
    1641           0 : bool file_find_subpath(files_struct *dir_fsp)
    1642             : {
    1643             :         files_struct *fsp;
    1644             :         size_t dlen;
    1645           0 :         char *d_fullname = NULL;
    1646             : 
    1647           0 :         d_fullname = talloc_asprintf(talloc_tos(), "%s/%s",
    1648           0 :                                      dir_fsp->conn->connectpath,
    1649           0 :                                      dir_fsp->fsp_name->base_name);
    1650             : 
    1651           0 :         if (!d_fullname) {
    1652           0 :                 return false;
    1653             :         }
    1654             : 
    1655           0 :         dlen = strlen(d_fullname);
    1656             : 
    1657           0 :         for (fsp=dir_fsp->conn->sconn->files; fsp; fsp=fsp->next) {
    1658             :                 char *d1_fullname;
    1659             : 
    1660           0 :                 if (fsp == dir_fsp) {
    1661           0 :                         continue;
    1662             :                 }
    1663             : 
    1664           0 :                 d1_fullname = talloc_asprintf(talloc_tos(),
    1665             :                                         "%s/%s",
    1666           0 :                                         fsp->conn->connectpath,
    1667           0 :                                         fsp->fsp_name->base_name);
    1668             : 
    1669             :                 /*
    1670             :                  * If the open file has a path that is a longer
    1671             :                  * component, then it's a subpath.
    1672             :                  */
    1673           0 :                 if (strnequal(d_fullname, d1_fullname, dlen) &&
    1674           0 :                                 (d1_fullname[dlen] == '/')) {
    1675           0 :                         TALLOC_FREE(d1_fullname);
    1676           0 :                         TALLOC_FREE(d_fullname);
    1677           0 :                         return true;
    1678             :                 }
    1679           0 :                 TALLOC_FREE(d1_fullname);
    1680             :         }
    1681             : 
    1682           0 :         TALLOC_FREE(d_fullname);
    1683           0 :         return false;
    1684             : }
    1685             : 
    1686             : /****************************************************************************
    1687             :  Free up a fsp.
    1688             : ****************************************************************************/
    1689             : 
    1690      146114 : static void fsp_free(files_struct *fsp)
    1691             : {
    1692      146114 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
    1693             : 
    1694      146114 :         if (fsp == sconn->fsp_fi_cache.fsp) {
    1695           4 :                 ZERO_STRUCT(sconn->fsp_fi_cache);
    1696             :         }
    1697             : 
    1698      146114 :         DLIST_REMOVE(sconn->files, fsp);
    1699      146114 :         SMB_ASSERT(sconn->num_files > 0);
    1700      146114 :         sconn->num_files--;
    1701             : 
    1702      146114 :         TALLOC_FREE(fsp->fake_file_handle);
    1703             : 
    1704      146114 :         if (fh_get_refcount(fsp->fh) == 1) {
    1705      146114 :                 TALLOC_FREE(fsp->fh);
    1706             :         } else {
    1707           0 :                 size_t new_refcount = fh_get_refcount(fsp->fh) - 1;
    1708           0 :                 fh_set_refcount(fsp->fh, new_refcount);
    1709             :         }
    1710             : 
    1711      146114 :         if (fsp->lease != NULL) {
    1712           0 :                 if (fsp->lease->ref_count == 1) {
    1713           0 :                         TALLOC_FREE(fsp->lease);
    1714             :                 } else {
    1715           0 :                         fsp->lease->ref_count--;
    1716             :                 }
    1717             :         }
    1718             : 
    1719      146114 :         fsp->conn->num_files_open--;
    1720             : 
    1721      252684 :         if (fsp->fsp_name != NULL &&
    1722      142088 :             fsp->fsp_name->fsp_link != NULL)
    1723             :         {
    1724             :                 /*
    1725             :                  * Free fsp_link of fsp->fsp_name. To do this in the correct
    1726             :                  * talloc destructor order we have to do it here. The
    1727             :                  * talloc_free() of the link should set the fsp pointer to NULL.
    1728             :                  */
    1729      129167 :                 TALLOC_FREE(fsp->fsp_name->fsp_link);
    1730      129167 :                 SMB_ASSERT(fsp->fsp_name->fsp == NULL);
    1731             :         }
    1732             : 
    1733             :         /* this is paranoia, just in case someone tries to reuse the
    1734             :            information */
    1735      146114 :         ZERO_STRUCTP(fsp);
    1736             : 
    1737             :         /* fsp->fsp_name is a talloc child and is free'd automatically. */
    1738      146114 :         TALLOC_FREE(fsp);
    1739      146114 : }
    1740             : 
    1741             : /*
    1742             :  * Rundown of all smb-related sub-structures of an fsp
    1743             :  */
    1744      162530 : void fsp_unbind_smb(struct smb_request *req, files_struct *fsp)
    1745             : {
    1746      162530 :         if (fsp == fsp->conn->cwd_fsp) {
    1747           0 :                 return;
    1748             :         }
    1749             : 
    1750      162530 :         if (fsp->notify) {
    1751          30 :                 size_t len = fsp_fullbasepath(fsp, NULL, 0);
    1752          30 :                 char fullpath[len+1];
    1753             : 
    1754          30 :                 fsp_fullbasepath(fsp, fullpath, sizeof(fullpath));
    1755             : 
    1756             :                 /*
    1757             :                  * Avoid /. at the end of the path name. notify can't
    1758             :                  * deal with it.
    1759             :                  */
    1760          42 :                 if (len > 1 && fullpath[len-1] == '.' &&
    1761          24 :                     fullpath[len-2] == '/') {
    1762          24 :                         fullpath[len-2] = '\0';
    1763             :                 }
    1764             : 
    1765          30 :                 notify_remove(fsp->conn->sconn->notify_ctx, fsp, fullpath);
    1766          30 :                 TALLOC_FREE(fsp->notify);
    1767             :         }
    1768             : 
    1769             :         /* Ensure this event will never fire. */
    1770      162530 :         TALLOC_FREE(fsp->update_write_time_event);
    1771             : 
    1772      162530 :         if (fsp->op != NULL) {
    1773       16339 :                 fsp->op->compat = NULL;
    1774             :         }
    1775      162530 :         TALLOC_FREE(fsp->op);
    1776             : 
    1777      162530 :         if ((req != NULL) && (fsp == req->chain_fsp)) {
    1778       16063 :                 req->chain_fsp = NULL;
    1779             :         }
    1780             : 
    1781             :         /*
    1782             :          * Clear all possible chained fsp
    1783             :          * pointers in the SMB2 request queue.
    1784             :          */
    1785      162530 :         remove_smb2_chained_fsp(fsp);
    1786             : }
    1787             : 
    1788      146114 : void file_free(struct smb_request *req, files_struct *fsp)
    1789             : {
    1790      146114 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
    1791      146114 :         uint64_t fnum = fsp->fnum;
    1792             : 
    1793      146114 :         fsp_unbind_smb(req, fsp);
    1794             : 
    1795             :         /* Drop all remaining extensions. */
    1796      146114 :         vfs_remove_all_fsp_extensions(fsp);
    1797             : 
    1798      146114 :         fsp_free(fsp);
    1799             : 
    1800      146114 :         DBG_INFO("freed files structure %"PRIu64" (%zu used)\n",
    1801             :                  fnum,
    1802             :                  sconn->num_files);
    1803      146114 : }
    1804             : 
    1805             : /****************************************************************************
    1806             :  Get an fsp from a packet given a 16 bit fnum.
    1807             : ****************************************************************************/
    1808             : 
    1809           0 : files_struct *file_fsp(struct smb_request *req, uint16_t fid)
    1810             : {
    1811             :         struct smbXsrv_open *op;
    1812             :         NTSTATUS status;
    1813           0 :         NTTIME now = 0;
    1814             :         files_struct *fsp;
    1815             : 
    1816           0 :         if (req == NULL) {
    1817             :                 /*
    1818             :                  * We should never get here. req==NULL could in theory
    1819             :                  * only happen from internal opens with a non-zero
    1820             :                  * root_dir_fid. Internal opens just don't do that, at
    1821             :                  * least they are not supposed to do so. And if they
    1822             :                  * start to do so, they better fake up a smb_request
    1823             :                  * from which we get the right smbd_server_conn. While
    1824             :                  * this should never happen, let's return NULL here.
    1825             :                  */
    1826           0 :                 return NULL;
    1827             :         }
    1828             : 
    1829           0 :         if (req->chain_fsp != NULL) {
    1830           0 :                 if (req->chain_fsp->fsp_flags.closing) {
    1831           0 :                         return NULL;
    1832             :                 }
    1833           0 :                 return req->chain_fsp;
    1834             :         }
    1835             : 
    1836           0 :         if (req->xconn == NULL) {
    1837           0 :                 return NULL;
    1838             :         }
    1839             : 
    1840           0 :         now = timeval_to_nttime(&req->request_time);
    1841             : 
    1842           0 :         status = smb1srv_open_lookup(req->xconn,
    1843             :                                      fid, now, &op);
    1844           0 :         if (!NT_STATUS_IS_OK(status)) {
    1845           0 :                 return NULL;
    1846             :         }
    1847             : 
    1848           0 :         fsp = op->compat;
    1849           0 :         if (fsp == NULL) {
    1850           0 :                 return NULL;
    1851             :         }
    1852             : 
    1853           0 :         if (fsp->fsp_flags.closing) {
    1854           0 :                 return NULL;
    1855             :         }
    1856             : 
    1857           0 :         req->chain_fsp = fsp;
    1858           0 :         return fsp;
    1859             : }
    1860             : 
    1861      114138 : struct files_struct *file_fsp_get(struct smbd_smb2_request *smb2req,
    1862             :                                   uint64_t persistent_id,
    1863             :                                   uint64_t volatile_id)
    1864             : {
    1865             :         struct smbXsrv_open *op;
    1866             :         NTSTATUS status;
    1867      114138 :         NTTIME now = 0;
    1868             :         struct files_struct *fsp;
    1869             : 
    1870      114138 :         now = timeval_to_nttime(&smb2req->request_time);
    1871             : 
    1872      114138 :         status = smb2srv_open_lookup(smb2req->xconn,
    1873             :                                      persistent_id, volatile_id,
    1874             :                                      now, &op);
    1875      114138 :         if (!NT_STATUS_IS_OK(status)) {
    1876        1661 :                 return NULL;
    1877             :         }
    1878             : 
    1879      112477 :         fsp = op->compat;
    1880      112477 :         if (fsp == NULL) {
    1881           0 :                 return NULL;
    1882             :         }
    1883             : 
    1884      112477 :         if (smb2req->tcon == NULL) {
    1885           0 :                 return NULL;
    1886             :         }
    1887             : 
    1888      112477 :         if (smb2req->tcon->compat != fsp->conn) {
    1889           0 :                 return NULL;
    1890             :         }
    1891             : 
    1892      112477 :         if (smb2req->session == NULL) {
    1893           0 :                 return NULL;
    1894             :         }
    1895             : 
    1896      112477 :         if (smb2req->session->global->session_wire_id != fsp->vuid) {
    1897           0 :                 return NULL;
    1898             :         }
    1899             : 
    1900      112477 :         if (fsp->fsp_flags.closing) {
    1901           0 :                 return NULL;
    1902             :         }
    1903             : 
    1904      112477 :         return fsp;
    1905             : }
    1906             : 
    1907      226611 : struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
    1908             :                                    uint64_t persistent_id,
    1909             :                                    uint64_t volatile_id)
    1910             : {
    1911             :         struct files_struct *fsp;
    1912             : 
    1913      226611 :         if (smb2req->compat_chain_fsp != NULL) {
    1914      112473 :                 if (smb2req->compat_chain_fsp->fsp_flags.closing) {
    1915           0 :                         return NULL;
    1916             :                 }
    1917      112473 :                 return smb2req->compat_chain_fsp;
    1918             :         }
    1919             : 
    1920      114138 :         fsp = file_fsp_get(smb2req, persistent_id, volatile_id);
    1921      114138 :         if (fsp == NULL) {
    1922        1661 :                 return NULL;
    1923             :         }
    1924             : 
    1925      112477 :         smb2req->compat_chain_fsp = fsp;
    1926      112477 :         return fsp;
    1927             : }
    1928             : 
    1929             : /****************************************************************************
    1930             :  Duplicate the file handle part for a DOS or FCB open.
    1931             : ****************************************************************************/
    1932             : 
    1933           0 : NTSTATUS dup_file_fsp(
    1934             :         files_struct *from,
    1935             :         uint32_t access_mask,
    1936             :         files_struct *to)
    1937             : {
    1938             :         size_t new_refcount;
    1939             : 
    1940             :         /* this can never happen for print files */
    1941           0 :         SMB_ASSERT(from->print_file == NULL);
    1942             : 
    1943           0 :         TALLOC_FREE(to->fh);
    1944             : 
    1945           0 :         to->fh = from->fh;
    1946           0 :         new_refcount = fh_get_refcount(to->fh) + 1;
    1947           0 :         fh_set_refcount(to->fh, new_refcount);
    1948             : 
    1949           0 :         to->file_id = from->file_id;
    1950           0 :         to->initial_allocation_size = from->initial_allocation_size;
    1951           0 :         to->file_pid = from->file_pid;
    1952           0 :         to->vuid = from->vuid;
    1953           0 :         to->open_time = from->open_time;
    1954           0 :         to->access_mask = access_mask;
    1955           0 :         to->oplock_type = from->oplock_type;
    1956           0 :         to->fsp_flags.can_lock = from->fsp_flags.can_lock;
    1957           0 :         to->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
    1958           0 :         to->fsp_flags.can_write =
    1959           0 :                 CAN_WRITE(from->conn) &&
    1960           0 :                 ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
    1961           0 :         to->fsp_flags.modified = from->fsp_flags.modified;
    1962           0 :         to->fsp_flags.is_directory = from->fsp_flags.is_directory;
    1963           0 :         to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind;
    1964           0 :         to->fsp_flags.is_fsa = from->fsp_flags.is_fsa;
    1965           0 :         to->fsp_flags.is_pathref = from->fsp_flags.is_pathref;
    1966           0 :         to->fsp_flags.have_proc_fds = from->fsp_flags.have_proc_fds;
    1967           0 :         to->fsp_flags.is_dirfsp = from->fsp_flags.is_dirfsp;
    1968             : 
    1969           0 :         return fsp_set_smb_fname(to, from->fsp_name);
    1970             : }
    1971             : 
    1972             : /**
    1973             :  * Return a jenkins hash of a pathname on a connection.
    1974             :  */
    1975             : 
    1976      129256 : NTSTATUS file_name_hash(connection_struct *conn,
    1977             :                         const char *name, uint32_t *p_name_hash)
    1978             : {
    1979             :         char tmpbuf[PATH_MAX];
    1980             :         char *fullpath, *to_free;
    1981             :         ssize_t len;
    1982             :         TDB_DATA key;
    1983             : 
    1984             :         /* Set the hash of the full pathname. */
    1985             : 
    1986      129256 :         if (name[0] == '/') {
    1987       35617 :                 strlcpy(tmpbuf, name, sizeof(tmpbuf));
    1988       35617 :                 fullpath = tmpbuf;
    1989       35617 :                 len = strlen(fullpath);
    1990       35617 :                 to_free = NULL;
    1991             :         } else {
    1992       93639 :                 len = full_path_tos(conn->connectpath,
    1993             :                                     name,
    1994             :                                     tmpbuf,
    1995             :                                     sizeof(tmpbuf),
    1996             :                                     &fullpath,
    1997             :                                     &to_free);
    1998             :         }
    1999      129256 :         if (len == -1) {
    2000           0 :                 return NT_STATUS_NO_MEMORY;
    2001             :         }
    2002      129256 :         key = (TDB_DATA) { .dptr = (uint8_t *)fullpath, .dsize = len+1 };
    2003      129256 :         *p_name_hash = tdb_jenkins_hash(&key);
    2004             : 
    2005      129256 :         DEBUG(10,("file_name_hash: %s hash 0x%x\n",
    2006             :                   fullpath,
    2007             :                 (unsigned int)*p_name_hash ));
    2008             : 
    2009      129256 :         TALLOC_FREE(to_free);
    2010      129256 :         return NT_STATUS_OK;
    2011             : }
    2012             : 
    2013      129219 : static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
    2014             :                                      struct smb_filename **_smb_fname)
    2015             : {
    2016      129219 :         struct smb_filename *smb_fname_new = talloc_move(fsp, _smb_fname);
    2017      129219 :         const char *name_str = NULL;
    2018      129219 :         uint32_t name_hash = 0;
    2019             :         NTSTATUS status;
    2020             : 
    2021      129219 :         name_str = smb_fname_str_dbg(smb_fname_new);
    2022      129219 :         if (name_str == NULL) {
    2023           0 :                 return NT_STATUS_NO_MEMORY;
    2024             :         }
    2025             : 
    2026      129219 :         status = file_name_hash(fsp->conn,
    2027             :                                 name_str,
    2028             :                                 &name_hash);
    2029      129219 :         if (!NT_STATUS_IS_OK(status)) {
    2030           0 :                 return status;
    2031             :         }
    2032             : 
    2033      129219 :         status = fsp_smb_fname_link(fsp,
    2034             :                                     &smb_fname_new->fsp_link,
    2035             :                                     &smb_fname_new->fsp);
    2036      129219 :         if (!NT_STATUS_IS_OK(status)) {
    2037           0 :                 return status;
    2038             :         }
    2039             : 
    2040      129219 :         fsp->name_hash = name_hash;
    2041      129219 :         fsp->fsp_name = smb_fname_new;
    2042      129219 :         *_smb_fname = NULL;
    2043      129219 :         return NT_STATUS_OK;
    2044             : }
    2045             : 
    2046             : /**
    2047             :  * The only way that the fsp->fsp_name field should ever be set.
    2048             :  */
    2049       16019 : NTSTATUS fsp_set_smb_fname(struct files_struct *fsp,
    2050             :                            const struct smb_filename *smb_fname_in)
    2051             : {
    2052       16019 :         struct smb_filename *smb_fname_old = fsp->fsp_name;
    2053       16019 :         struct smb_filename *smb_fname_new = NULL;
    2054             :         NTSTATUS status;
    2055             : 
    2056       16019 :         smb_fname_new = cp_smb_filename(fsp, smb_fname_in);
    2057       16019 :         if (smb_fname_new == NULL) {
    2058           0 :                 return NT_STATUS_NO_MEMORY;
    2059             :         }
    2060             : 
    2061       16019 :         status = fsp_attach_smb_fname(fsp, &smb_fname_new);
    2062       16019 :         if (!NT_STATUS_IS_OK(status)) {
    2063           0 :                 TALLOC_FREE(smb_fname_new);
    2064           0 :                 return status;
    2065             :         }
    2066             : 
    2067       16019 :         if (smb_fname_old != NULL) {
    2068        9497 :                 smb_fname_fsp_unlink(smb_fname_old);
    2069        9497 :                 TALLOC_FREE(smb_fname_old);
    2070             :         }
    2071             : 
    2072       16019 :         return NT_STATUS_OK;
    2073             : }
    2074             : 
    2075         120 : size_t fsp_fullbasepath(struct files_struct *fsp, char *buf, size_t buflen)
    2076             : {
    2077         120 :         int len = 0;
    2078         120 :         char tmp_buf[1] = {'\0'};
    2079             : 
    2080             :         /*
    2081             :          * Don't pass NULL buffer to snprintf (to satisfy static checker)
    2082             :          * Some callers will call this function with NULL for buf and
    2083             :          * 0 for buflen in order to get length of fullbasepath (without
    2084             :          * needing to allocate or write to buf)
    2085             :          */
    2086         120 :         if (buf == NULL) {
    2087          60 :                 buf = tmp_buf;
    2088          60 :                 SMB_ASSERT(buflen==0);
    2089             :         }
    2090             : 
    2091         120 :         len = snprintf(buf, buflen, "%s/%s", fsp->conn->connectpath,
    2092         120 :                        fsp->fsp_name->base_name);
    2093         120 :         SMB_ASSERT(len>0);
    2094             : 
    2095         120 :         return len;
    2096             : }
    2097             : 
    2098      126652 : void fsp_set_base_fsp(struct files_struct *fsp, struct files_struct *base_fsp)
    2099             : {
    2100      126652 :         SMB_ASSERT(fsp->stream_fsp == NULL);
    2101      126652 :         if (base_fsp != NULL) {
    2102         136 :                 SMB_ASSERT(base_fsp->base_fsp == NULL);
    2103         136 :                 SMB_ASSERT(base_fsp->stream_fsp == NULL);
    2104             :         }
    2105             : 
    2106      126652 :         if (fsp->base_fsp != NULL) {
    2107          72 :                 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
    2108          72 :                 fsp->base_fsp->stream_fsp = NULL;
    2109             :         }
    2110             : 
    2111      126652 :         fsp->base_fsp = base_fsp;
    2112      126652 :         if (fsp->base_fsp != NULL) {
    2113         136 :                 fsp->base_fsp->stream_fsp = fsp;
    2114             :         }
    2115      126652 : }
    2116             : 
    2117      495310 : bool fsp_is_alternate_stream(const struct files_struct *fsp)
    2118             : {
    2119      495310 :         return (fsp->base_fsp != NULL);
    2120             : }
    2121             : 
    2122       59568 : struct files_struct *metadata_fsp(struct files_struct *fsp)
    2123             : {
    2124       59568 :         if (fsp_is_alternate_stream(fsp)) {
    2125         270 :                 return fsp->base_fsp;
    2126             :         }
    2127       59298 :         return fsp;
    2128             : }

Generated by: LCOV version 1.13