LCOV - code coverage report
Current view: top level - source3/smbd - files.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 1013 1195 84.8 %
Date: 2024-04-13 12:30:31 Functions: 61 61 100.0 %

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

Generated by: LCOV version 1.14