LCOV - code coverage report
Current view: top level - source3/smbd - files.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 640 902 71.0 %
Date: 2024-02-14 10:14:15 Functions: 50 55 90.9 %

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

Generated by: LCOV version 1.14