LCOV - code coverage report
Current view: top level - source3/smbd - files.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 1007 1190 84.6 %
Date: 2024-04-21 15:09:00 Functions: 60 60 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     6284198 : NTSTATUS fsp_new(struct connection_struct *conn, TALLOC_CTX *mem_ctx,
      40             :                  files_struct **result)
      41             : {
      42     6284198 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
      43     6284198 :         files_struct *fsp = NULL;
      44     6284198 :         struct smbd_server_connection *sconn = conn->sconn;
      45             : 
      46     6284198 :         fsp = talloc_zero(mem_ctx, struct files_struct);
      47     6284198 :         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     6284198 :         fsp->fh = fd_handle_create(mem_ctx);
      57     6284198 :         if (fsp->fh == NULL) {
      58           0 :                 goto fail;
      59             :         }
      60             : 
      61     6284198 :         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     6284198 :         fh_set_refcount(fsp->fh, 1);
      67     6284198 :         fsp_set_fd(fsp, -1);
      68             : 
      69     6284198 :         fsp->fnum = FNUM_FIELD_INVALID;
      70     6284198 :         fsp->conn = conn;
      71     6284198 :         fsp->close_write_time = make_omit_timespec();
      72             : 
      73     6284198 :         DLIST_ADD(sconn->files, fsp);
      74     6284198 :         sconn->num_files += 1;
      75             : 
      76     6284198 :         conn->num_files_open++;
      77             : 
      78     6284198 :         DBG_INFO("allocated files structure (%u used)\n",
      79             :                 (unsigned int)sconn->num_files);
      80             : 
      81     6284198 :         *result = fsp;
      82     6284198 :         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     6134432 : 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     6134432 :         gen_id++;
     102     6134432 :         fh_set_gen_id(fsp->fh, gen_id);
     103     6134432 : }
     104             : 
     105             : /****************************************************************************
     106             :  Find first available file slot.
     107             : ****************************************************************************/
     108             : 
     109      875171 : NTSTATUS fsp_bind_smb(struct files_struct *fsp, struct smb_request *req)
     110             : {
     111      875171 :         struct smbXsrv_open *op = NULL;
     112        3078 :         NTTIME now;
     113        3078 :         NTSTATUS status;
     114             : 
     115      875171 :         if (req == NULL) {
     116      307192 :                 DBG_DEBUG("INTERNAL_OPEN_ONLY, skipping smbXsrv_open\n");
     117      307192 :                 return NT_STATUS_OK;
     118             :         }
     119             : 
     120      567979 :         now = timeval_to_nttime(&fsp->open_time);
     121             : 
     122      567979 :         status = smbXsrv_open_create(req->xconn,
     123      567979 :                                      fsp->conn->session_info,
     124             :                                      now,
     125             :                                      &op);
     126      567979 :         if (!NT_STATUS_IS_OK(status)) {
     127           2 :                 return status;
     128             :         }
     129      567977 :         fsp->op = op;
     130      567977 :         op->compat = fsp;
     131      567977 :         fsp->fnum = op->local_id;
     132             : 
     133      567977 :         fsp->mid = req->mid;
     134      567977 :         req->chain_fsp = fsp;
     135             : 
     136      567977 :         DBG_DEBUG("fsp [%s] mid [%" PRIu64"]\n",
     137             :                 fsp_str_dbg(fsp), fsp->mid);
     138             : 
     139      567977 :         return NT_STATUS_OK;
     140             : }
     141             : 
     142      583696 : NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
     143             :                   files_struct **result)
     144             : {
     145      583696 :         struct smbd_server_connection *sconn = conn->sconn;
     146        2129 :         files_struct *fsp;
     147        2129 :         NTSTATUS status;
     148             : 
     149      583696 :         status = fsp_new(conn, conn, &fsp);
     150      583696 :         if (!NT_STATUS_IS_OK(status)) {
     151           0 :                 return status;
     152             :         }
     153             : 
     154      583696 :         GetTimeOfDay(&fsp->open_time);
     155             : 
     156      583696 :         status = fsp_bind_smb(fsp, req);
     157      583696 :         if (!NT_STATUS_IS_OK(status)) {
     158           2 :                 file_free(NULL, fsp);
     159           2 :                 return status;
     160             :         }
     161             : 
     162      583694 :         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      583694 :         fsp->fsp_name = synthetic_smb_fname(fsp,
     170             :                                             "",
     171             :                                             NULL,
     172             :                                             NULL,
     173             :                                             0,
     174             :                                             0);
     175      583694 :         if (fsp->fsp_name == NULL) {
     176           0 :                 file_free(NULL, fsp);
     177           0 :                 return NT_STATUS_NO_MEMORY;
     178             :         }
     179             : 
     180      583694 :         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      583694 :         ZERO_STRUCT(sconn->fsp_fi_cache);
     188             : 
     189      583694 :         *result = fsp;
     190      583694 :         return NT_STATUS_OK;
     191             : }
     192             : 
     193      298790 : NTSTATUS create_internal_fsp(connection_struct *conn,
     194             :                              const struct smb_filename *smb_fname,
     195             :                              struct files_struct **_fsp)
     196             : {
     197      298790 :         struct files_struct *fsp = NULL;
     198         957 :         NTSTATUS status;
     199             : 
     200      298790 :         status = file_new(NULL, conn, &fsp);
     201      298790 :         if (!NT_STATUS_IS_OK(status)) {
     202           0 :                 return status;
     203             :         }
     204             : 
     205      298790 :         status = fsp_set_smb_fname(fsp, smb_fname);
     206      298790 :         if (!NT_STATUS_IS_OK(status)) {
     207           0 :                 file_free(NULL, fsp);
     208           0 :                 return status;
     209             :         }
     210             : 
     211      298790 :         *_fsp = fsp;
     212      298790 :         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      289576 : NTSTATUS create_internal_dirfsp(connection_struct *conn,
     222             :                                 const struct smb_filename *smb_dname,
     223             :                                 struct files_struct **_fsp)
     224             : {
     225      289576 :         struct files_struct *fsp = NULL;
     226         957 :         NTSTATUS status;
     227             : 
     228      289576 :         status = create_internal_fsp(conn, smb_dname, &fsp);
     229      289576 :         if (!NT_STATUS_IS_OK(status)) {
     230           0 :                 return status;
     231             :         }
     232             : 
     233      289576 :         fsp->access_mask = FILE_LIST_DIRECTORY;
     234      289576 :         fsp->fsp_flags.is_directory = true;
     235      289576 :         fsp->fsp_flags.is_dirfsp = true;
     236             : 
     237      289576 :         *_fsp = fsp;
     238      289576 :         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      273549 : NTSTATUS openat_internal_dir_from_pathref(
     294             :         struct files_struct *dirfsp,
     295             :         int _open_flags,
     296             :         struct files_struct **_fsp)
     297             : {
     298      273549 :         struct connection_struct *conn = dirfsp->conn;
     299      273549 :         struct smb_filename *smb_dname = dirfsp->fsp_name;
     300      273549 :         struct files_struct *fsp = NULL;
     301      273549 :         char dot[] = ".";
     302      273549 :         struct smb_filename smb_dot = {
     303             :                 .base_name = dot,
     304      273549 :                 .flags = smb_dname->flags,
     305      273549 :                 .twrp = smb_dname->twrp,
     306             :         };
     307      273549 :         struct vfs_open_how how = { .flags = _open_flags, };
     308         883 :         NTSTATUS status;
     309             : 
     310      273549 :         status = create_internal_dirfsp(conn, smb_dname, &fsp);
     311      273549 :         if (!NT_STATUS_IS_OK(status)) {
     312           0 :                 return status;
     313             :         }
     314             : 
     315             :         /*
     316             :          * Pointless for opening ".", but you never know...
     317             :          */
     318      273549 :         how.flags |= O_NOFOLLOW;
     319             : 
     320      273549 :         status = fd_openat(dirfsp, &smb_dot, fsp, &how);
     321      273549 :         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      273548 :         fsp->fsp_name->st = smb_dname->st;
     330      273548 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     331      273548 :         *_fsp = fsp;
     332      273548 :         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     6083805 : static int fsp_smb_fname_link_destructor(struct fsp_smb_fname_link *link)
     356             : {
     357     6083805 :         if (link->smb_fname_link == NULL) {
     358           0 :                 return 0;
     359             :         }
     360             : 
     361     6083805 :         *link->smb_fname_link = NULL;
     362     6083805 :         *link->smb_fname_fsp = NULL;
     363     6083805 :         return 0;
     364             : }
     365             : 
     366    10305371 : 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    10305371 :         struct fsp_smb_fname_link *link = NULL;
     371             : 
     372    10305371 :         SMB_ASSERT(*smb_fname_link == NULL);
     373    10305371 :         SMB_ASSERT(*smb_fname_fsp == NULL);
     374             : 
     375    10305371 :         link = talloc_zero(fsp, struct fsp_smb_fname_link);
     376    10305371 :         if (link == NULL) {
     377           0 :                 return NT_STATUS_NO_MEMORY;
     378             :         }
     379             : 
     380    10305371 :         link->smb_fname_link = smb_fname_link;
     381    10305371 :         link->smb_fname_fsp = smb_fname_fsp;
     382    10305371 :         *smb_fname_link = link;
     383    10305371 :         *smb_fname_fsp = fsp;
     384             : 
     385    10305371 :         talloc_set_destructor(link, fsp_smb_fname_link_destructor);
     386    10305371 :         return NT_STATUS_OK;
     387             : }
     388             : 
     389             : /*
     390             :  * Free a link, carefully avoiding to trigger the link destructor
     391             :  */
     392     5437693 : static void destroy_fsp_smb_fname_link(struct fsp_smb_fname_link **_link)
     393             : {
     394     5437693 :         struct fsp_smb_fname_link *link = *_link;
     395             : 
     396     5437693 :         if (link == NULL) {
     397     1203612 :                 return;
     398             :         }
     399     4221546 :         talloc_set_destructor(link, NULL);
     400     4221546 :         TALLOC_FREE(link);
     401     4221546 :         *_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     3400219 : static int smb_fname_fsp_destructor(struct smb_filename *smb_fname)
     409             : {
     410     3400219 :         struct files_struct *fsp = smb_fname->fsp;
     411     3400219 :         struct files_struct *base_fsp = NULL;
     412       23276 :         NTSTATUS status;
     413     3400219 :         int saved_errno = errno;
     414             : 
     415     3400219 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
     416             : 
     417     3400219 :         if (fsp == NULL) {
     418        8824 :                 errno = saved_errno;
     419        8824 :                 return 0;
     420             :         }
     421             : 
     422     3391395 :         if (fsp_is_alternate_stream(fsp)) {
     423         775 :                 base_fsp = fsp->base_fsp;
     424             :         }
     425             : 
     426     3391395 :         status = fd_close(fsp);
     427     3391395 :         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     3391395 :         file_free(NULL, fsp);
     433     3391395 :         smb_fname->fsp = NULL;
     434             : 
     435     3391395 :         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     3391395 :         errno = saved_errno;
     447     3391395 :         return 0;
     448             : }
     449             : 
     450     3422577 : 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     3422577 :         struct files_struct *fsp = NULL;
     459     3422577 :         bool have_dirfsp = (dirfsp != NULL);
     460     3422577 :         bool have_basefsp = (basefsp != NULL);
     461       10525 :         NTSTATUS status;
     462             : 
     463     3422577 :         DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
     464             : 
     465     3422577 :         SMB_ASSERT(smb_fname->fsp == NULL);
     466     3422577 :         SMB_ASSERT(have_dirfsp != have_basefsp);
     467             : 
     468     3422577 :         status = fsp_new(conn, conn, &fsp);
     469     3422577 :         if (!NT_STATUS_IS_OK(status)) {
     470           0 :                 return status;
     471             :         }
     472             : 
     473     3422577 :         GetTimeOfDay(&fsp->open_time);
     474     3422577 :         fsp_set_gen_id(fsp);
     475     3422577 :         ZERO_STRUCT(conn->sconn->fsp_fi_cache);
     476             : 
     477     3422577 :         fsp->fsp_flags.is_pathref = true;
     478             : 
     479     3422577 :         status = fsp_attach_smb_fname(fsp, full_fname);
     480     3422577 :         if (!NT_STATUS_IS_OK(status)) {
     481           0 :                 goto fail;
     482             :         }
     483     3422577 :         fsp_set_base_fsp(fsp, basefsp);
     484             : 
     485     3422577 :         status = fd_openat(dirfsp, smb_fname, fsp, how);
     486     3422577 :         if (!NT_STATUS_IS_OK(status)) {
     487             : 
     488     1516978 :                 smb_fname->st = fsp->fsp_name->st;
     489             : 
     490     1516978 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ||
     491     1515552 :                     NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
     492     1510486 :                     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     1516978 :                 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     1905599 :         smb_fname->st = fsp->fsp_name->st;
     520             : 
     521     1905599 :         fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
     522             : 
     523     1905599 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
     524             : 
     525     1905599 :         status = fsp_smb_fname_link(fsp,
     526             :                                     &smb_fname->fsp_link,
     527             :                                     &smb_fname->fsp);
     528     1905599 :         if (!NT_STATUS_IS_OK(status)) {
     529           0 :                 goto fail;
     530             :         }
     531             : 
     532     1905599 :         DBG_DEBUG("fsp [%s]: OK\n", fsp_str_dbg(fsp));
     533             : 
     534     1905599 :         talloc_set_destructor(smb_fname, smb_fname_fsp_destructor);
     535     1905599 :         return NT_STATUS_OK;
     536             : 
     537     1516978 : fail:
     538     1516978 :         DBG_DEBUG("Opening pathref for [%s] failed: %s\n",
     539             :                   smb_fname_str_dbg(smb_fname),
     540             :                   nt_errstr(status));
     541             : 
     542     1516978 :         fsp_set_base_fsp(fsp, NULL);
     543     1516978 :         fd_close(fsp);
     544     1516978 :         file_free(NULL, fsp);
     545     1516978 :         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     3414822 : NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
     555             :                             struct smb_filename *smb_fname)
     556             : {
     557     3414822 :         connection_struct *conn = dirfsp->conn;
     558     3414822 :         struct smb_filename *full_fname = NULL;
     559     3414822 :         struct smb_filename *base_fname = NULL;
     560     3414822 :         struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
     561       10543 :         NTSTATUS status;
     562             : 
     563     3414822 :         DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
     564             : 
     565     3414822 :         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     3414372 :         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     3414372 :         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     3412395 :                 full_fname = full_path_from_dirfsp_atname(
     587             :                         conn,
     588             :                         dirfsp,
     589             :                         smb_fname);
     590     3412395 :                 if (full_fname == NULL) {
     591           0 :                         status = NT_STATUS_NO_MEMORY;
     592           0 :                         goto fail;
     593             :                 }
     594     3412395 :                 status = openat_pathref_fullname(
     595             :                         conn, dirfsp, NULL, &full_fname, smb_fname, &how);
     596     3412395 :                 TALLOC_FREE(full_fname);
     597     3412395 :                 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        8205 : NTSTATUS open_stream_pathref_fsp(
     645             :         struct files_struct **_base_fsp,
     646             :         struct smb_filename *smb_fname)
     647             : {
     648        8205 :         struct files_struct *base_fsp = *_base_fsp;
     649        8205 :         connection_struct *conn = base_fsp->conn;
     650        8205 :         struct smb_filename *base_fname = base_fsp->fsp_name;
     651        8205 :         struct smb_filename *full_fname = NULL;
     652        8205 :         struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
     653           4 :         NTSTATUS status;
     654             : 
     655        8205 :         SMB_ASSERT(smb_fname->fsp == NULL);
     656        8205 :         SMB_ASSERT(is_named_stream(smb_fname));
     657             : 
     658       16410 :         full_fname = synthetic_smb_fname(
     659             :                 conn, /* no talloc_tos(), this will be long-lived */
     660        8205 :                 base_fname->base_name,
     661        8205 :                 smb_fname->stream_name,
     662        8205 :                 &smb_fname->st,
     663             :                 smb_fname->twrp,
     664             :                 smb_fname->flags);
     665        8205 :         if (full_fname == NULL) {
     666           0 :                 return NT_STATUS_NO_MEMORY;
     667             :         }
     668             : 
     669        8205 :         status = openat_pathref_fullname(
     670             :                 conn, NULL, base_fsp, &full_fname, smb_fname, &how);
     671        8205 :         TALLOC_FREE(full_fname);
     672        8205 :         return status;
     673             : }
     674             : 
     675      570963 : static char *path_to_strv(TALLOC_CTX *mem_ctx, const char *path)
     676             : {
     677      570963 :         char *result = talloc_strdup(mem_ctx, path);
     678             : 
     679      570963 :         if (result == NULL) {
     680           0 :                 return NULL;
     681             :         }
     682      570963 :         string_replace(result, '/', '\0');
     683      570963 :         return result;
     684             : }
     685             : 
     686       73959 : NTSTATUS readlink_talloc(
     687             :         TALLOC_CTX *mem_ctx,
     688             :         struct files_struct *dirfsp,
     689             :         struct smb_filename *smb_relname,
     690             :         char **_substitute)
     691             : {
     692       73959 :         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       73959 :         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       38671 :                 smb_relname = &null_fname;
     706             :         }
     707             : 
     708       73959 :         ret = SMB_VFS_READLINKAT(
     709             :                 dirfsp->conn, dirfsp, smb_relname, buf, sizeof(buf));
     710       73959 :         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       73943 :         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       73943 :         substitute = talloc_strndup(mem_ctx, buf, ret);
     727       73943 :         if (substitute == NULL) {
     728           0 :                 DBG_DEBUG("talloc_strndup() failed\n");
     729           0 :                 return NT_STATUS_NO_MEMORY;
     730             :         }
     731             : 
     732       73943 :         *_substitute = substitute;
     733       73943 :         return NT_STATUS_OK;
     734             : }
     735             : 
     736       71598 : NTSTATUS read_symlink_reparse(TALLOC_CTX *mem_ctx,
     737             :                               struct files_struct *dirfsp,
     738             :                               struct smb_filename *smb_relname,
     739             :                               struct reparse_data_buffer **_reparse)
     740             : {
     741       71598 :         struct reparse_data_buffer *reparse = NULL;
     742       71598 :         struct symlink_reparse_struct *lnk = NULL;
     743           0 :         NTSTATUS status;
     744             : 
     745       71598 :         reparse = talloc_zero(mem_ctx, struct reparse_data_buffer);
     746       71598 :         if (reparse == NULL) {
     747           0 :                 goto nomem;
     748             :         }
     749       71598 :         *reparse = (struct reparse_data_buffer){
     750             :                 .tag = IO_REPARSE_TAG_SYMLINK,
     751             :         };
     752       71598 :         lnk = &reparse->parsed.lnk;
     753             : 
     754       71598 :         status = readlink_talloc(reparse,
     755             :                                  dirfsp,
     756             :                                  smb_relname,
     757             :                                  &lnk->substitute_name);
     758       71598 :         if (!NT_STATUS_IS_OK(status)) {
     759          16 :                 DBG_DEBUG("readlink_talloc failed: %s\n", nt_errstr(status));
     760          16 :                 goto fail;
     761             :         }
     762             : 
     763       71582 :         if (lnk->substitute_name[0] == '/') {
     764       18744 :                 char *subdir_path = NULL;
     765       18744 :                 char *abs_target_canon = NULL;
     766       18744 :                 const char *relative = NULL;
     767           0 :                 bool in_share;
     768             : 
     769       18744 :                 subdir_path = talloc_asprintf(talloc_tos(),
     770             :                                               "%s/%s",
     771       18744 :                                               dirfsp->conn->connectpath,
     772       18744 :                                               dirfsp->fsp_name->base_name);
     773       18744 :                 if (subdir_path == NULL) {
     774           0 :                         goto nomem;
     775             :                 }
     776             : 
     777       18744 :                 abs_target_canon = canonicalize_absolute_path(
     778       18744 :                         talloc_tos(), lnk->substitute_name);
     779       18744 :                 if (abs_target_canon == NULL) {
     780           0 :                         goto nomem;
     781             :                 }
     782             : 
     783       18744 :                 in_share = subdir_of(subdir_path,
     784             :                                      strlen(subdir_path),
     785             :                                      abs_target_canon,
     786             :                                      &relative);
     787       18744 :                 if (in_share) {
     788        7484 :                         TALLOC_FREE(lnk->substitute_name);
     789        7484 :                         lnk->substitute_name = talloc_strdup(reparse,
     790             :                                                              relative);
     791        7484 :                         if (lnk->substitute_name == NULL) {
     792           0 :                                 goto nomem;
     793             :                         }
     794             :                 }
     795             :         }
     796             : 
     797       71582 :         if (!IS_DIRECTORY_SEP(lnk->substitute_name[0])) {
     798       60322 :                 lnk->flags |= SYMLINK_FLAG_RELATIVE;
     799             :         }
     800             : 
     801       71582 :         *_reparse = reparse;
     802       71582 :         return NT_STATUS_OK;
     803           0 : nomem:
     804           0 :         status = NT_STATUS_NO_MEMORY;
     805          16 : fail:
     806          16 :         TALLOC_FREE(reparse);
     807          16 :         return status;
     808             : }
     809             : 
     810      682643 : static bool full_path_extend(char **dir, const char *atname)
     811             : {
     812      682643 :         talloc_asprintf_addbuf(dir,
     813             :                                "%s%s",
     814      682643 :                                (*dir)[0] == '\0' ? "" : "/",
     815             :                                atname);
     816      682643 :         return (*dir) != NULL;
     817             : }
     818             : 
     819             : /*
     820             :  * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
     821             :  * the stat cache for the last component to be looked up. Cache
     822             :  * contents is the correctly capitalized translation of the parameter
     823             :  * "name" as it exists on disk. This is indexed by inode of the dirfsp
     824             :  * and name, and contrary to stat_cahce_lookup() it does not
     825             :  * vfs_stat() the last component. This will be taken care of by an
     826             :  * attempt to do a openat_pathref_fsp().
     827             :  */
     828      270557 : static bool get_real_filename_cache_key(TALLOC_CTX *mem_ctx,
     829             :                                         struct files_struct *dirfsp,
     830             :                                         const char *name,
     831             :                                         DATA_BLOB *_key)
     832             : {
     833      270557 :         struct file_id fid = vfs_file_id_from_sbuf(dirfsp->conn,
     834      270557 :                                                    &dirfsp->fsp_name->st);
     835      270557 :         char *upper = NULL;
     836      270557 :         uint8_t *key = NULL;
     837         885 :         size_t namelen, keylen;
     838             : 
     839      270557 :         upper = talloc_strdup_upper(mem_ctx, name);
     840      270557 :         if (upper == NULL) {
     841           0 :                 return false;
     842             :         }
     843      270557 :         namelen = talloc_get_size(upper);
     844             : 
     845      270557 :         keylen = namelen + sizeof(fid);
     846      270557 :         if (keylen < sizeof(fid)) {
     847           0 :                 TALLOC_FREE(upper);
     848           0 :                 return false;
     849             :         }
     850             : 
     851      270557 :         key = talloc_size(mem_ctx, keylen);
     852      270557 :         if (key == NULL) {
     853           0 :                 TALLOC_FREE(upper);
     854           0 :                 return false;
     855             :         }
     856             : 
     857      270557 :         memcpy(key, &fid, sizeof(fid));
     858      270557 :         memcpy(key + sizeof(fid), upper, namelen);
     859      270557 :         TALLOC_FREE(upper);
     860             : 
     861      270557 :         *_key = (DATA_BLOB){
     862             :                 .data = key,
     863             :                 .length = keylen,
     864             :         };
     865      270557 :         return true;
     866             : }
     867             : 
     868     2081621 : static int smb_vfs_openat_ci(TALLOC_CTX *mem_ctx,
     869             :                              bool case_sensitive,
     870             :                              struct connection_struct *conn,
     871             :                              struct files_struct *dirfsp,
     872             :                              struct smb_filename *smb_fname_rel,
     873             :                              files_struct *fsp,
     874             :                              const struct vfs_open_how *how)
     875             : {
     876     2081621 :         char *orig_base_name = smb_fname_rel->base_name;
     877     2081621 :         DATA_BLOB cache_key = {
     878             :                 .data = NULL,
     879             :         };
     880     2081621 :         DATA_BLOB cache_value = {
     881             :                 .data = NULL,
     882             :         };
     883       19632 :         NTSTATUS status;
     884       19632 :         int fd;
     885       19632 :         bool ok;
     886             : 
     887     2081621 :         fd = SMB_VFS_OPENAT(conn, dirfsp, smb_fname_rel, fsp, how);
     888     2081621 :         if ((fd >= 0) || case_sensitive) {
     889     1730191 :                 return fd;
     890             :         }
     891      332683 :         if (errno != ENOENT) {
     892       62126 :                 return -1;
     893             :         }
     894             : 
     895      270557 :         if (!lp_stat_cache()) {
     896           0 :                 goto lookup;
     897             :         }
     898             : 
     899      270557 :         ok = get_real_filename_cache_key(mem_ctx,
     900             :                                          dirfsp,
     901             :                                          orig_base_name,
     902             :                                          &cache_key);
     903      270557 :         if (!ok) {
     904             :                 /*
     905             :                  * probably ENOMEM, just bail
     906             :                  */
     907           0 :                 errno = ENOMEM;
     908           0 :                 return -1;
     909             :         }
     910             : 
     911      270557 :         DO_PROFILE_INC(statcache_lookups);
     912             : 
     913      270557 :         ok = memcache_lookup(NULL,
     914             :                              GETREALFILENAME_CACHE,
     915             :                              cache_key,
     916             :                              &cache_value);
     917      270557 :         if (!ok) {
     918      268588 :                 DO_PROFILE_INC(statcache_misses);
     919      268588 :                 goto lookup;
     920             :         }
     921        1969 :         DO_PROFILE_INC(statcache_hits);
     922             : 
     923        3938 :         smb_fname_rel->base_name = talloc_strndup(mem_ctx,
     924        1969 :                                                   (char *)cache_value.data,
     925             :                                                   cache_value.length);
     926        1969 :         if (smb_fname_rel->base_name == NULL) {
     927           0 :                 TALLOC_FREE(cache_key.data);
     928           0 :                 smb_fname_rel->base_name = orig_base_name;
     929           0 :                 errno = ENOMEM;
     930           0 :                 return -1;
     931             :         }
     932             : 
     933        1969 :         if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
     934           0 :                 DBG_DEBUG("veto files rejecting last component %s\n",
     935             :                           smb_fname_str_dbg(smb_fname_rel));
     936           0 :                 TALLOC_FREE(cache_key.data);
     937           0 :                 smb_fname_rel->base_name = orig_base_name;
     938           0 :                 errno = EPERM;
     939           0 :                 return -1;
     940             :         }
     941             : 
     942        1969 :         fd = SMB_VFS_OPENAT(conn, dirfsp, smb_fname_rel, fsp, how);
     943        1969 :         if (fd >= 0) {
     944        1892 :                 TALLOC_FREE(cache_key.data);
     945        1892 :                 return fd;
     946             :         }
     947             : 
     948          77 :         memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
     949             : 
     950             :         /*
     951             :          * For the "new filename" case we need to preserve the
     952             :          * capitalization the client sent us, see
     953             :          * https://bugzilla.samba.org/show_bug.cgi?id=15481
     954             :          */
     955          77 :         TALLOC_FREE(smb_fname_rel->base_name);
     956          77 :         smb_fname_rel->base_name = orig_base_name;
     957             : 
     958      268665 : lookup:
     959             : 
     960      268665 :         status = get_real_filename_at(dirfsp,
     961             :                                       orig_base_name,
     962             :                                       mem_ctx,
     963             :                                       &smb_fname_rel->base_name);
     964      268665 :         if (!NT_STATUS_IS_OK(status)) {
     965      267060 :                 DBG_DEBUG("get_real_filename_at() failed: %s\n",
     966             :                           nt_errstr(status));
     967      267060 :                 errno = ENOENT;
     968      267060 :                 return -1;
     969             :         }
     970             : 
     971        1605 :         if (IS_VETO_PATH(conn, smb_fname_rel->base_name)) {
     972          24 :                 DBG_DEBUG("found veto files path component "
     973             :                           "%s => %s\n",
     974             :                           orig_base_name,
     975             :                           smb_fname_rel->base_name);
     976          24 :                 TALLOC_FREE(smb_fname_rel->base_name);
     977          24 :                 smb_fname_rel->base_name = orig_base_name;
     978          24 :                 errno = ENOENT;
     979          24 :                 return -1;
     980             :         }
     981             : 
     982        1581 :         fd = SMB_VFS_OPENAT(conn, dirfsp, smb_fname_rel, fsp, how);
     983             : 
     984        1581 :         if ((fd >= 0) && (cache_key.data != NULL)) {
     985        1497 :                 DATA_BLOB value = {
     986        1497 :                         .data = (uint8_t *)smb_fname_rel->base_name,
     987        1497 :                         .length = strlen(smb_fname_rel->base_name) + 1,
     988             :                 };
     989             : 
     990        1497 :                 memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
     991        1497 :                 TALLOC_FREE(cache_key.data);
     992             :         }
     993             : 
     994        1577 :         return fd;
     995             : }
     996             : 
     997      570963 : NTSTATUS openat_pathref_fsp_nosymlink(
     998             :         TALLOC_CTX *mem_ctx,
     999             :         struct connection_struct *conn,
    1000             :         struct files_struct *in_dirfsp,
    1001             :         const char *path_in,
    1002             :         NTTIME twrp,
    1003             :         bool posix,
    1004             :         struct smb_filename **_smb_fname,
    1005             :         struct reparse_data_buffer **_symlink_err)
    1006             : {
    1007      570963 :         struct files_struct *dirfsp = in_dirfsp;
    1008     1141926 :         struct smb_filename full_fname = {
    1009             :                 .base_name = NULL,
    1010             :                 .twrp = twrp,
    1011      570963 :                 .flags = posix ? SMB_FILENAME_POSIX_PATH : 0,
    1012             :         };
    1013      570963 :         struct smb_filename rel_fname = {
    1014             :                 .base_name = NULL,
    1015             :                 .twrp = twrp,
    1016      562054 :                 .flags = full_fname.flags,
    1017             :         };
    1018      570963 :         struct smb_filename *result = NULL;
    1019      570963 :         struct reparse_data_buffer *symlink_err = NULL;
    1020      570963 :         struct files_struct *fsp = NULL;
    1021      570963 :         char *path = NULL, *next = NULL;
    1022        8909 :         bool ok, is_toplevel;
    1023        8909 :         int fd;
    1024        8909 :         NTSTATUS status;
    1025      570963 :         struct vfs_open_how how = {
    1026             :                 .flags = O_NOFOLLOW | O_NONBLOCK,
    1027             :                 .mode = 0,
    1028             :         };
    1029             : 
    1030      570963 :         DBG_DEBUG("path_in=%s\n", path_in);
    1031             : 
    1032      570963 :         status = fsp_new(conn, conn, &fsp);
    1033      570963 :         if (!NT_STATUS_IS_OK(status)) {
    1034           0 :                 DBG_DEBUG("fsp_new() failed: %s\n", nt_errstr(status));
    1035           0 :                 goto fail;
    1036             :         }
    1037             : 
    1038      570963 :         GetTimeOfDay(&fsp->open_time);
    1039      570963 :         fsp_set_gen_id(fsp);
    1040      570963 :         ZERO_STRUCT(conn->sconn->fsp_fi_cache);
    1041             : 
    1042      570963 :         fsp->fsp_name = &full_fname;
    1043             : 
    1044             : #ifdef O_PATH
    1045             :         /*
    1046             :          * Add O_PATH manually, doing this by setting
    1047             :          * fsp->fsp_flags.is_pathref will make us become_root() in the
    1048             :          * non-O_PATH case, which would cause a security problem.
    1049             :          */
    1050      388172 :         how.flags |= O_PATH;
    1051             : #else
    1052             : #ifdef O_SEARCH
    1053             :         /*
    1054             :          * O_SEARCH just checks for the "x" bit. We are traversing
    1055             :          * directories, so we don't need the implicit O_RDONLY ("r"
    1056             :          * permissions) but only the "x"-permissions requested by
    1057             :          * O_SEARCH. We need either O_PATH or O_SEARCH to correctly
    1058             :          * function, without either we will incorrectly require also
    1059             :          * the "r" bit when traversing the directory hierarchy.
    1060             :          */
    1061             :         how.flags |= O_SEARCH;
    1062             : #endif
    1063             : #endif
    1064             : 
    1065      570963 :         is_toplevel = (dirfsp == dirfsp->conn->cwd_fsp);
    1066      570963 :         is_toplevel |= ISDOT(dirfsp->fsp_name->base_name);
    1067             : 
    1068      579872 :         full_fname.base_name =
    1069      570963 :                 talloc_strdup(talloc_tos(),
    1070           0 :                               is_toplevel ? "" : dirfsp->fsp_name->base_name);
    1071      570963 :         if (full_fname.base_name == NULL) {
    1072           0 :                 DBG_DEBUG("talloc_strdup() failed\n");
    1073           0 :                 goto nomem;
    1074             :         }
    1075             : 
    1076             :         /*
    1077             :          * First split the path into individual components.
    1078             :          */
    1079      570963 :         path = path_to_strv(talloc_tos(), path_in);
    1080      570963 :         if (path == NULL) {
    1081           0 :                 DBG_DEBUG("path_to_strv() failed\n");
    1082           0 :                 goto nomem;
    1083             :         }
    1084             : 
    1085             :         /*
    1086             :          * First we loop over all components
    1087             :          * in order to verify, there's no '.' or '..'
    1088             :          */
    1089      570963 :         rel_fname.base_name = path;
    1090     2186893 :         while (rel_fname.base_name != NULL) {
    1091             : 
    1092     1615948 :                 next = strv_next(path, rel_fname.base_name);
    1093             : 
    1094             :                 /*
    1095             :                  * Path sanitizing further up has cleaned or rejected
    1096             :                  * empty path components. Assert this here.
    1097             :                  */
    1098     1615948 :                 SMB_ASSERT(rel_fname.base_name[0] != '\0');
    1099             : 
    1100     1615948 :                 if (ISDOT(rel_fname.base_name) ||
    1101     1607035 :                     ISDOTDOT(rel_fname.base_name)) {
    1102           0 :                         DBG_DEBUG("%s contains a dot\n", path_in);
    1103           0 :                         status = NT_STATUS_OBJECT_NAME_INVALID;
    1104           0 :                         goto fail;
    1105             :                 }
    1106             : 
    1107             :                 /* Check veto files. */
    1108     1615948 :                 if (IS_VETO_PATH(conn, rel_fname.base_name)) {
    1109          18 :                         DBG_DEBUG("%s contains veto files path component %s\n",
    1110             :                                   path_in, rel_fname.base_name);
    1111          18 :                         status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
    1112          18 :                         goto fail;
    1113             :                 }
    1114             : 
    1115     1615930 :                 rel_fname.base_name = next;
    1116             :         }
    1117             : 
    1118      570945 :         if (conn->open_how_resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
    1119             : 
    1120             :                 /*
    1121             :                  * Try a direct openat2 with RESOLVE_NO_SYMLINKS to
    1122             :                  * avoid the openat/close loop further down.
    1123             :                  */
    1124             : 
    1125      261921 :                 rel_fname.base_name = discard_const_p(char, path_in);
    1126      261921 :                 how.resolve = VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
    1127             : 
    1128      261921 :                 fd = SMB_VFS_OPENAT(conn, dirfsp, &rel_fname, fsp, &how);
    1129      261921 :                 if (fd >= 0) {
    1130      217460 :                         fsp_set_fd(fsp, fd);
    1131      217460 :                         ok = full_path_extend(&full_fname.base_name,
    1132      217460 :                                               rel_fname.base_name);
    1133      217460 :                         if (!ok) {
    1134           0 :                                 goto nomem;
    1135             :                         }
    1136      217460 :                         goto done;
    1137             :                 }
    1138             : 
    1139       44461 :                 status = map_nt_error_from_unix(errno);
    1140       44461 :                 DBG_DEBUG("SMB_VFS_OPENAT(%s, %s, RESOLVE_NO_SYMLINKS) "
    1141             :                           "returned %d %s => %s\n",
    1142             :                           smb_fname_str_dbg(dirfsp->fsp_name), path_in,
    1143             :                           errno, strerror(errno), nt_errstr(status));
    1144       44461 :                 SMB_ASSERT(fd == -1);
    1145       44461 :                 switch (errno) {
    1146       26165 :                 case ENOSYS:
    1147             :                         /*
    1148             :                          * We got ENOSYS, so fallback to the old code
    1149             :                          * if the kernel doesn't support openat2() yet.
    1150             :                          */
    1151       26165 :                         break;
    1152             : 
    1153       16945 :                 case ELOOP:
    1154             :                 case ENOTDIR:
    1155             :                         /*
    1156             :                          * For ELOOP we also fallback in order to
    1157             :                          * return the correct information with
    1158             :                          * NT_STATUS_STOPPED_ON_SYMLINK.
    1159             :                          *
    1160             :                          * O_NOFOLLOW|O_DIRECTORY results in
    1161             :                          * ENOTDIR instead of ELOOP for the final
    1162             :                          * component.
    1163             :                          */
    1164       16945 :                         break;
    1165             : 
    1166        1303 :                 case ENOENT:
    1167             :                         /*
    1168             :                          * If we got ENOENT, the filesystem could
    1169             :                          * be case sensitive. For now we only do
    1170             :                          * the get_real_filename_at() dance in
    1171             :                          * the fallback loop below.
    1172             :                          */
    1173        1303 :                         break;
    1174             : 
    1175           3 :                 default:
    1176           3 :                         goto fail;
    1177             :                 }
    1178             : 
    1179             :                 /*
    1180             :                  * Just fallback to the openat loop
    1181             :                  */
    1182       44458 :                 how.resolve = 0;
    1183             :         }
    1184             : 
    1185             :         /*
    1186             :          * Now we loop over all components
    1187             :          * opening each one and using it
    1188             :          * as dirfd for the next one.
    1189             :          *
    1190             :          * It means we can detect symlinks
    1191             :          * within the path.
    1192             :          */
    1193      353482 :         rel_fname.base_name = path;
    1194      524561 : next:
    1195      524561 :         next = strv_next(path, rel_fname.base_name);
    1196             : 
    1197      524561 :         fd = smb_vfs_openat_ci(talloc_tos(),
    1198      524561 :                                posix || conn->case_sensitive,
    1199             :                                conn,
    1200             :                                dirfsp,
    1201             :                                &rel_fname,
    1202             :                                fsp,
    1203             :                                &how);
    1204             : 
    1205             : #ifndef O_PATH
    1206      253946 :         if ((fd == -1) && (errno == ELOOP)) {
    1207             :                 int ret;
    1208             : 
    1209             :                 /*
    1210             :                  * openat() hit a symlink. With O_PATH we open the
    1211             :                  * symlink and get ENOTDIR in the next round, see
    1212             :                  * below.
    1213             :                  */
    1214             : 
    1215       24798 :                 status = read_symlink_reparse(mem_ctx,
    1216             :                                               dirfsp,
    1217             :                                               &rel_fname,
    1218             :                                               &symlink_err);
    1219       24798 :                 if (!NT_STATUS_IS_OK(status)) {
    1220           0 :                         DBG_DEBUG("read_symlink_reparse failed: %s\n",
    1221             :                                   nt_errstr(status));
    1222           0 :                         goto fail;
    1223             :                 }
    1224             : 
    1225       24798 :                 if (next != NULL) {
    1226       22245 :                         size_t parsed = next - path;
    1227       22245 :                         size_t len = talloc_get_size(path);
    1228       22245 :                         size_t unparsed = len - parsed;
    1229             : 
    1230       22245 :                         if (unparsed > UINT16_MAX) {
    1231           0 :                                 status = NT_STATUS_BUFFER_OVERFLOW;
    1232           0 :                                 goto fail;
    1233             :                         }
    1234       22245 :                         symlink_err->parsed.lnk
    1235       22245 :                                 .unparsed_path_length = unparsed;
    1236             :                 }
    1237             : 
    1238             :                 /*
    1239             :                  * We know rel_fname is a symlink, now fill in the
    1240             :                  * rest of the metadata for our callers.
    1241             :                  */
    1242             : 
    1243       24798 :                 ret = SMB_VFS_FSTATAT(conn,
    1244             :                                       dirfsp,
    1245             :                                       &rel_fname,
    1246             :                                       &full_fname.st,
    1247             :                                       AT_SYMLINK_NOFOLLOW);
    1248       24798 :                 if (ret == -1) {
    1249           0 :                         status = map_nt_error_from_unix(errno);
    1250           0 :                         DBG_DEBUG("SMB_VFS_FSTATAT(%s/%s) failed: %s\n",
    1251             :                                   fsp_str_dbg(dirfsp),
    1252             :                                   rel_fname.base_name,
    1253             :                                   strerror(errno));
    1254           0 :                         TALLOC_FREE(symlink_err);
    1255           0 :                         goto fail;
    1256             :                 }
    1257             : 
    1258       24798 :                 if (!S_ISLNK(full_fname.st.st_ex_mode)) {
    1259             :                         /*
    1260             :                          * Hit a race: readlink_talloc() worked before
    1261             :                          * the fstatat(), but rel_fname changed to
    1262             :                          * something that's not a symlink.
    1263             :                          */
    1264           0 :                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1265           0 :                         TALLOC_FREE(symlink_err);
    1266           0 :                         goto fail;
    1267             :                 }
    1268             : 
    1269       24798 :                 status = NT_STATUS_STOPPED_ON_SYMLINK;
    1270       24798 :                 goto fail;
    1271             :         }
    1272             : #endif
    1273             : 
    1274      499763 :         if ((fd == -1) && (errno == ENOTDIR)) {
    1275           0 :                 size_t parsed, len, unparsed;
    1276             : 
    1277             :                 /*
    1278             :                  * dirfsp does not point at a directory, try a
    1279             :                  * freadlink.
    1280             :                  */
    1281             : 
    1282       33589 :                 status = read_symlink_reparse(mem_ctx,
    1283             :                                               dirfsp,
    1284             :                                               NULL,
    1285             :                                               &symlink_err);
    1286             : 
    1287       33589 :                 if (!NT_STATUS_IS_OK(status)) {
    1288          16 :                         DBG_DEBUG("read_symlink_reparse failed: %s\n",
    1289             :                                   nt_errstr(status));
    1290          16 :                         status = NT_STATUS_NOT_A_DIRECTORY;
    1291          16 :                         goto fail;
    1292             :                 }
    1293             : 
    1294       33573 :                 parsed = rel_fname.base_name - path;
    1295       33573 :                 len = talloc_get_size(path);
    1296       33573 :                 unparsed = len - parsed;
    1297             : 
    1298       33573 :                 if (unparsed > UINT16_MAX) {
    1299           0 :                         status = NT_STATUS_BUFFER_OVERFLOW;
    1300           0 :                         goto fail;
    1301             :                 }
    1302             : 
    1303       33573 :                 symlink_err->parsed.lnk.unparsed_path_length = unparsed;
    1304             : 
    1305       33573 :                 status = NT_STATUS_STOPPED_ON_SYMLINK;
    1306       33573 :                 goto fail;
    1307             :         }
    1308             : 
    1309      466174 :         if (fd == -1) {
    1310         991 :                 status = map_nt_error_from_unix(errno);
    1311         991 :                 DBG_DEBUG("SMB_VFS_OPENAT() failed: %s\n",
    1312             :                           strerror(errno));
    1313         991 :                 goto fail;
    1314             :         }
    1315      465183 :         fsp_set_fd(fsp, fd);
    1316             : 
    1317      465183 :         ok = full_path_extend(&full_fname.base_name, rel_fname.base_name);
    1318      465183 :         if (!ok) {
    1319           0 :                 goto nomem;
    1320             :         }
    1321             : 
    1322      465183 :         if (next != NULL) {
    1323      171079 :                 struct files_struct *tmp = NULL;
    1324             : 
    1325      171079 :                 if (dirfsp != in_dirfsp) {
    1326       21315 :                         fd_close(dirfsp);
    1327             :                 }
    1328             : 
    1329      171079 :                 tmp = dirfsp;
    1330      171079 :                 dirfsp = fsp;
    1331             : 
    1332      171079 :                 if (tmp == in_dirfsp) {
    1333      149764 :                         status = fsp_new(conn, conn, &fsp);
    1334      149764 :                         if (!NT_STATUS_IS_OK(status)) {
    1335           0 :                                 DBG_DEBUG("fsp_new() failed: %s\n",
    1336             :                                           nt_errstr(status));
    1337           0 :                                 goto fail;
    1338             :                         }
    1339      149764 :                         fsp->fsp_name = &full_fname;
    1340             :                 } else {
    1341       21315 :                         fsp = tmp;
    1342             :                 }
    1343             : 
    1344      171079 :                 rel_fname.base_name = next;
    1345             : 
    1346      171079 :                 goto next;
    1347             :         }
    1348             : 
    1349      294104 :         if (dirfsp != in_dirfsp) {
    1350      109215 :                 SMB_ASSERT(fsp_get_pathref_fd(dirfsp) != -1);
    1351      109215 :                 fd_close(dirfsp);
    1352      109215 :                 dirfsp->fsp_name = NULL;
    1353      109215 :                 file_free(NULL, dirfsp);
    1354      109215 :                 dirfsp = NULL;
    1355             :         }
    1356             : 
    1357      184889 : done:
    1358      511564 :         fsp->fsp_flags.is_pathref = true;
    1359      511564 :         fsp->fsp_name = NULL;
    1360             : 
    1361      511564 :         status = fsp_set_smb_fname(fsp, &full_fname);
    1362      511564 :         if (!NT_STATUS_IS_OK(status)) {
    1363           0 :                 DBG_DEBUG("fsp_set_smb_fname() failed: %s\n",
    1364             :                           nt_errstr(status));
    1365           0 :                 goto fail;
    1366             :         }
    1367             : 
    1368      511564 :         status = vfs_stat_fsp(fsp);
    1369      511564 :         if (!NT_STATUS_IS_OK(status)) {
    1370           0 :                 DBG_DEBUG("vfs_stat_fsp(%s) failed: %s\n",
    1371             :                           fsp_str_dbg(fsp),
    1372             :                           nt_errstr(status));
    1373           0 :                 goto fail;
    1374             :         }
    1375             : 
    1376      511564 :         if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
    1377             :                 /*
    1378             :                  * Last component was a symlink we opened with O_PATH, fail it
    1379             :                  * here.
    1380             :                  */
    1381        3723 :                 status = read_symlink_reparse(mem_ctx,
    1382             :                                               fsp,
    1383             :                                               NULL,
    1384             :                                               &symlink_err);
    1385        3723 :                 if (!NT_STATUS_IS_OK(status)) {
    1386           0 :                         return status;
    1387             :                 }
    1388             : 
    1389        3723 :                 status = NT_STATUS_STOPPED_ON_SYMLINK;
    1390        3723 :                 goto fail;
    1391             :         }
    1392             : 
    1393             :         /*
    1394             :          * We must correctly set fsp->file_id as code inside
    1395             :          * open.c will use this to check if delete_on_close
    1396             :          * has been set on the dirfsp.
    1397             :          */
    1398      507841 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
    1399             : 
    1400      507841 :         result = cp_smb_filename(mem_ctx, fsp->fsp_name);
    1401      507841 :         if (result == NULL) {
    1402           0 :                 DBG_DEBUG("cp_smb_filename() failed\n");
    1403           0 :                 goto nomem;
    1404             :         }
    1405             : 
    1406      507841 :         status = fsp_smb_fname_link(fsp,
    1407             :                                         &result->fsp_link,
    1408             :                                         &result->fsp);
    1409      507841 :         if (!NT_STATUS_IS_OK(status)) {
    1410           0 :                 goto fail;
    1411             :         }
    1412      507841 :         talloc_set_destructor(result, smb_fname_fsp_destructor);
    1413             : 
    1414      507841 :         *_smb_fname = result;
    1415             : 
    1416      507841 :         DBG_DEBUG("returning %s\n", smb_fname_str_dbg(result));
    1417             : 
    1418      507841 :         return NT_STATUS_OK;
    1419             : 
    1420           0 : nomem:
    1421           0 :         status = NT_STATUS_NO_MEMORY;
    1422       63122 : fail:
    1423       63122 :         if (fsp != NULL) {
    1424       63122 :                 if (fsp_get_pathref_fd(fsp) != -1) {
    1425        3723 :                         fd_close(fsp);
    1426             :                 }
    1427       63122 :                 file_free(NULL, fsp);
    1428       63122 :                 fsp = NULL;
    1429             :         }
    1430             : 
    1431       63122 :         if ((dirfsp != NULL) && (dirfsp != in_dirfsp)) {
    1432       40549 :                 SMB_ASSERT(fsp_get_pathref_fd(dirfsp) != -1);
    1433       40549 :                 fd_close(dirfsp);
    1434       40549 :                 dirfsp->fsp_name = NULL;
    1435       40549 :                 file_free(NULL, dirfsp);
    1436       40549 :                 dirfsp = NULL;
    1437             :         }
    1438             : 
    1439       63122 :         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
    1440       62094 :                 *_symlink_err = symlink_err;
    1441             :         }
    1442             : 
    1443       63122 :         TALLOC_FREE(path);
    1444       63122 :         return status;
    1445             : }
    1446             : 
    1447             : /*
    1448             :  * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
    1449             :  * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
    1450             :  * the first attempt based on the filename sent by the client gives
    1451             :  * ENOENT.
    1452             :  */
    1453     1557074 : NTSTATUS openat_pathref_fsp_lcomp(struct files_struct *dirfsp,
    1454             :                                   struct smb_filename *smb_fname_rel,
    1455             :                                   uint32_t ucf_flags)
    1456             : {
    1457     1557074 :         struct connection_struct *conn = dirfsp->conn;
    1458     1557074 :         const char *orig_rel_base_name = smb_fname_rel->base_name;
    1459     1557074 :         struct files_struct *fsp = NULL;
    1460     1557074 :         struct smb_filename *full_fname = NULL;
    1461     1557074 :         struct vfs_open_how how = {
    1462             :                 .flags = O_RDONLY | O_NONBLOCK | O_NOFOLLOW,
    1463             :         };
    1464       10719 :         NTSTATUS status;
    1465       10719 :         int ret, fd;
    1466             : 
    1467             :         /*
    1468             :          * Make sure we don't need of the all the magic in
    1469             :          * openat_pathref_fsp() with regards non_widelink_open etc.
    1470             :          */
    1471             : 
    1472     1557074 :         SMB_ASSERT((smb_fname_rel->fsp == NULL) &&
    1473             :                    (dirfsp != dirfsp->conn->cwd_fsp) &&
    1474             :                    (strchr_m(smb_fname_rel->base_name, '/') == NULL) &&
    1475             :                    !is_named_stream(smb_fname_rel));
    1476             : 
    1477     1557074 :         SET_STAT_INVALID(smb_fname_rel->st);
    1478             : 
    1479             :         /* Check veto files - only looks at last component. */
    1480     1557074 :         if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
    1481          14 :                 DBG_DEBUG("veto files rejecting last component %s\n",
    1482             :                           smb_fname_str_dbg(smb_fname_rel));
    1483          14 :                 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
    1484             :         }
    1485             : 
    1486     1557060 :         status = fsp_new(conn, conn, &fsp);
    1487     1557060 :         if (!NT_STATUS_IS_OK(status)) {
    1488           0 :                 DBG_DEBUG("fsp_new() failed: %s\n", nt_errstr(status));
    1489           0 :                 return status;
    1490             :         }
    1491             : 
    1492     1557060 :         GetTimeOfDay(&fsp->open_time);
    1493     1557060 :         fsp_set_gen_id(fsp);
    1494     1557060 :         ZERO_STRUCT(conn->sconn->fsp_fi_cache);
    1495             : 
    1496     1557060 :         fsp->fsp_flags.is_pathref = true;
    1497             : 
    1498     1557060 :         full_fname = full_path_from_dirfsp_atname(conn, dirfsp, smb_fname_rel);
    1499     1557060 :         if (full_fname == NULL) {
    1500           0 :                 DBG_DEBUG("full_path_from_dirfsp_atname(%s/%s) failed\n",
    1501             :                           dirfsp->fsp_name->base_name,
    1502             :                           smb_fname_rel->base_name);
    1503           0 :                 file_free(NULL, fsp);
    1504           0 :                 return NT_STATUS_NO_MEMORY;
    1505             :         }
    1506             : 
    1507     1557060 :         status = fsp_attach_smb_fname(fsp, &full_fname);
    1508     1557060 :         if (!NT_STATUS_IS_OK(status)) {
    1509           0 :                 DBG_DEBUG("fsp_attach_smb_fname(fsp, %s) failed: %s\n",
    1510             :                           smb_fname_str_dbg(full_fname),
    1511             :                           nt_errstr(status));
    1512           0 :                 file_free(NULL, fsp);
    1513           0 :                 return status;
    1514             :         }
    1515             : 
    1516     3103401 :         fd = smb_vfs_openat_ci(smb_fname_rel,
    1517     2166123 :                                (ucf_flags & UCF_POSIX_PATHNAMES) ||
    1518      619467 :                                        conn->case_sensitive,
    1519             :                                conn,
    1520             :                                dirfsp,
    1521             :                                smb_fname_rel,
    1522             :                                fsp,
    1523             :                                &how);
    1524             : 
    1525     1557060 :         if ((fd == -1) && (errno == ENOENT)) {
    1526      268611 :                 status = map_nt_error_from_unix(errno);
    1527      268611 :                 DBG_DEBUG("smb_vfs_openat(%s/%s) failed: %s\n",
    1528             :                           dirfsp->fsp_name->base_name,
    1529             :                           smb_fname_rel->base_name,
    1530             :                           strerror(errno));
    1531      268611 :                 file_free(NULL, fsp);
    1532      268611 :                 return status;
    1533             :         }
    1534             : 
    1535     1288449 :         if (smb_fname_rel->base_name != orig_rel_base_name) {
    1536        2148 :                 struct smb_filename new_fullname = *smb_fname_rel;
    1537             : 
    1538        2148 :                 DBG_DEBUG("rel->base_name changed from %s to %s\n",
    1539             :                           orig_rel_base_name,
    1540             :                           smb_fname_rel->base_name);
    1541             : 
    1542        2148 :                 new_fullname.base_name = full_path_from_dirfsp_at_basename(
    1543        2148 :                         talloc_tos(), dirfsp, new_fullname.base_name);
    1544        2148 :                 if (new_fullname.base_name == NULL) {
    1545           0 :                         fd_close(fsp);
    1546           0 :                         file_free(NULL, fsp);
    1547           0 :                         return NT_STATUS_NO_MEMORY;
    1548             :                 }
    1549             : 
    1550        2148 :                 status = fsp_set_smb_fname(fsp, &new_fullname);
    1551        2148 :                 if (!NT_STATUS_IS_OK(status)) {
    1552           0 :                         fd_close(fsp);
    1553           0 :                         file_free(NULL, fsp);
    1554           0 :                         return status;
    1555             :                 }
    1556             :         }
    1557             : 
    1558     1288449 :         fsp_set_fd(fsp, fd);
    1559             : 
    1560     1288449 :         if (fd >= 0) {
    1561     1282899 :                 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
    1562             :         } else {
    1563        5550 :                 ret = SMB_VFS_FSTATAT(fsp->conn,
    1564             :                                       dirfsp,
    1565             :                                       smb_fname_rel,
    1566             :                                       &fsp->fsp_name->st,
    1567             :                                       AT_SYMLINK_NOFOLLOW);
    1568             :         }
    1569     1288449 :         if (ret == -1) {
    1570          12 :                 status = map_nt_error_from_unix(errno);
    1571          12 :                 DBG_DEBUG("SMB_VFS_%sSTAT(%s/%s) failed: %s\n",
    1572             :                           (fd >= 0) ? "F" : "",
    1573             :                           dirfsp->fsp_name->base_name,
    1574             :                           smb_fname_rel->base_name,
    1575             :                           strerror(errno));
    1576          12 :                 fd_close(fsp);
    1577          12 :                 file_free(NULL, fsp);
    1578          12 :                 return status;
    1579             :         }
    1580             : 
    1581     1288437 :         fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
    1582     1288437 :         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
    1583             : 
    1584     1288437 :         smb_fname_rel->st = fsp->fsp_name->st;
    1585             : 
    1586     1288437 :         status = fsp_smb_fname_link(fsp,
    1587             :                                     &smb_fname_rel->fsp_link,
    1588             :                                     &smb_fname_rel->fsp);
    1589     1288437 :         if (!NT_STATUS_IS_OK(status)) {
    1590           0 :                 DBG_DEBUG("fsp_smb_fname_link() failed: %s\n",
    1591             :                           nt_errstr(status));
    1592           0 :                 fd_close(fsp);
    1593           0 :                 file_free(NULL, fsp);
    1594           0 :                 return status;
    1595             :         }
    1596             : 
    1597     1288437 :         DBG_DEBUG("fsp [%s]: OK, fd=%d\n", fsp_str_dbg(fsp), fd);
    1598             : 
    1599     1288437 :         talloc_set_destructor(smb_fname_rel, smb_fname_fsp_destructor);
    1600     1288437 :         return NT_STATUS_OK;
    1601             : }
    1602             : 
    1603     1865814 : void smb_fname_fsp_unlink(struct smb_filename *smb_fname)
    1604             : {
    1605     1865814 :         talloc_set_destructor(smb_fname, NULL);
    1606     1865814 :         smb_fname->fsp = NULL;
    1607     1865814 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
    1608     1865814 : }
    1609             : 
    1610             : /*
    1611             :  * Move any existing embedded fsp refs from the src name to the
    1612             :  * destination. It's safe to call this on src smb_fname's that have no embedded
    1613             :  * pathref fsp.
    1614             :  */
    1615      351287 : NTSTATUS move_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,
    1616             :                                  struct smb_filename *smb_fname_src)
    1617             : {
    1618        9527 :         NTSTATUS status;
    1619             : 
    1620             :         /*
    1621             :          * The target should always not be linked yet!
    1622             :          */
    1623      351287 :         SMB_ASSERT(smb_fname_dst->fsp == NULL);
    1624      351287 :         SMB_ASSERT(smb_fname_dst->fsp_link == NULL);
    1625             : 
    1626      351287 :         if (smb_fname_src->fsp == NULL) {
    1627           0 :                 return NT_STATUS_OK;
    1628             :         }
    1629             : 
    1630      351287 :         status = fsp_smb_fname_link(smb_fname_src->fsp,
    1631             :                                     &smb_fname_dst->fsp_link,
    1632             :                                     &smb_fname_dst->fsp);
    1633      351287 :         if (!NT_STATUS_IS_OK(status)) {
    1634           0 :                 return status;
    1635             :         }
    1636             : 
    1637      351287 :         talloc_set_destructor(smb_fname_dst, smb_fname_fsp_destructor);
    1638             : 
    1639      351287 :         smb_fname_fsp_unlink(smb_fname_src);
    1640             : 
    1641      351287 :         return NT_STATUS_OK;
    1642             : }
    1643             : 
    1644      171660 : static int fsp_ref_no_close_destructor(struct smb_filename *smb_fname)
    1645             : {
    1646      171660 :         destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
    1647      171660 :         return 0;
    1648             : }
    1649             : 
    1650      175997 : NTSTATUS reference_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,
    1651             :                                       const struct smb_filename *smb_fname_src)
    1652             : {
    1653         377 :         NTSTATUS status;
    1654             : 
    1655             :         /*
    1656             :          * The target should always not be linked yet!
    1657             :          */
    1658      175997 :         SMB_ASSERT(smb_fname_dst->fsp == NULL);
    1659      175997 :         SMB_ASSERT(smb_fname_dst->fsp_link == NULL);
    1660             : 
    1661      175997 :         if (smb_fname_src->fsp == NULL) {
    1662        4337 :                 return NT_STATUS_OK;
    1663             :         }
    1664             : 
    1665      171660 :         status = fsp_smb_fname_link(smb_fname_src->fsp,
    1666             :                                     &smb_fname_dst->fsp_link,
    1667             :                                     &smb_fname_dst->fsp);
    1668      171660 :         if (!NT_STATUS_IS_OK(status)) {
    1669           0 :                 return status;
    1670             :         }
    1671             : 
    1672      171660 :         talloc_set_destructor(smb_fname_dst, fsp_ref_no_close_destructor);
    1673             : 
    1674      171660 :         return NT_STATUS_OK;
    1675             : }
    1676             : 
    1677             : /**
    1678             :  * Create an smb_fname and open smb_fname->fsp pathref
    1679             :  **/
    1680      343591 : NTSTATUS synthetic_pathref(TALLOC_CTX *mem_ctx,
    1681             :                            struct files_struct *dirfsp,
    1682             :                            const char *base_name,
    1683             :                            const char *stream_name,
    1684             :                            const SMB_STRUCT_STAT *psbuf,
    1685             :                            NTTIME twrp,
    1686             :                            uint32_t flags,
    1687             :                            struct smb_filename **_smb_fname)
    1688             : {
    1689      343591 :         struct smb_filename *smb_fname = NULL;
    1690        1958 :         NTSTATUS status;
    1691             : 
    1692      343591 :         smb_fname = synthetic_smb_fname(mem_ctx,
    1693             :                                         base_name,
    1694             :                                         stream_name,
    1695             :                                         psbuf,
    1696             :                                         twrp,
    1697             :                                         flags);
    1698      343591 :         if (smb_fname == NULL) {
    1699           0 :                 return NT_STATUS_NO_MEMORY;
    1700             :         }
    1701             : 
    1702      343591 :         status = openat_pathref_fsp(dirfsp, smb_fname);
    1703      343591 :         if (!NT_STATUS_IS_OK(status)) {
    1704      207257 :                 DBG_NOTICE("opening [%s] failed\n",
    1705             :                         smb_fname_str_dbg(smb_fname));
    1706      207257 :                 TALLOC_FREE(smb_fname);
    1707      207257 :                 return status;
    1708             :         }
    1709             : 
    1710      136334 :         *_smb_fname = smb_fname;
    1711      136334 :         return NT_STATUS_OK;
    1712             : }
    1713             : 
    1714             : /**
    1715             :  * Turn a path into a parent pathref and atname
    1716             :  *
    1717             :  * This returns the parent pathref in _parent and the name relative to it. If
    1718             :  * smb_fname was a pathref (ie smb_fname->fsp != NULL), then _atname will be a
    1719             :  * pathref as well, ie _atname->fsp will point at the same fsp as
    1720             :  * smb_fname->fsp.
    1721             :  **/
    1722      175065 : NTSTATUS parent_pathref(TALLOC_CTX *mem_ctx,
    1723             :                         struct files_struct *dirfsp,
    1724             :                         const struct smb_filename *smb_fname,
    1725             :                         struct smb_filename **_parent,
    1726             :                         struct smb_filename **_atname)
    1727             : {
    1728      175065 :         struct smb_filename *parent = NULL;
    1729      175065 :         struct smb_filename *atname = NULL;
    1730         361 :         NTSTATUS status;
    1731             : 
    1732      175065 :         status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
    1733             :                                          mem_ctx,
    1734             :                                          smb_fname,
    1735             :                                          &parent,
    1736             :                                          &atname);
    1737      175065 :         if (!NT_STATUS_IS_OK(status)) {
    1738           0 :                 return status;
    1739             :         }
    1740             : 
    1741             :         /*
    1742             :          * We know that the parent name must
    1743             :          * exist, and the name has been canonicalized
    1744             :          * even if this was a POSIX pathname.
    1745             :          * Ensure that we follow symlinks for
    1746             :          * the parent. See the torture test
    1747             :          * POSIX-SYMLINK-PARENT for details.
    1748             :          */
    1749      175065 :         parent->flags &= ~SMB_FILENAME_POSIX_PATH;
    1750             : 
    1751      175065 :         status = openat_pathref_fsp(dirfsp, parent);
    1752      175065 :         if (!NT_STATUS_IS_OK(status)) {
    1753           0 :                 TALLOC_FREE(parent);
    1754           0 :                 return status;
    1755             :         }
    1756             : 
    1757      175065 :         status = reference_smb_fname_fsp_link(atname, smb_fname);
    1758      175065 :         if (!NT_STATUS_IS_OK(status)) {
    1759           0 :                 TALLOC_FREE(parent);
    1760           0 :                 return status;
    1761             :         }
    1762             : 
    1763      175065 :         *_parent = parent;
    1764      175065 :         *_atname = atname;
    1765      175065 :         return NT_STATUS_OK;
    1766             : }
    1767             : 
    1768        3106 : static bool close_file_in_loop(struct files_struct *fsp,
    1769             :                                enum file_close_type close_type)
    1770             : {
    1771        3106 :         if (fsp_is_alternate_stream(fsp)) {
    1772             :                 /*
    1773             :                  * This is a stream, it can't be a base
    1774             :                  */
    1775          72 :                 SMB_ASSERT(fsp->stream_fsp == NULL);
    1776          72 :                 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
    1777             : 
    1778             :                 /*
    1779             :                  * Remove the base<->stream link so that
    1780             :                  * close_file_free() does not close fsp->base_fsp as
    1781             :                  * well. This would destroy walking the linked list of
    1782             :                  * fsps.
    1783             :                  */
    1784          72 :                 fsp->base_fsp->stream_fsp = NULL;
    1785          72 :                 fsp->base_fsp = NULL;
    1786             : 
    1787          72 :                 close_file_free(NULL, &fsp, close_type);
    1788          72 :                 return NULL;
    1789             :         }
    1790             : 
    1791        3034 :         if (fsp->stream_fsp != NULL) {
    1792             :                 /*
    1793             :                  * This is the base of a stream.
    1794             :                  */
    1795           0 :                 SMB_ASSERT(fsp->stream_fsp->base_fsp == fsp);
    1796             : 
    1797             :                 /*
    1798             :                  * Remove the base<->stream link. This will make fsp
    1799             :                  * look like a normal fsp for the next round.
    1800             :                  */
    1801           0 :                 fsp->stream_fsp->base_fsp = NULL;
    1802           0 :                 fsp->stream_fsp = NULL;
    1803             : 
    1804             :                 /*
    1805             :                  * Have us called back a second time. In the second
    1806             :                  * round, "fsp" now looks like a normal fsp.
    1807             :                  */
    1808           0 :                 return false;
    1809             :         }
    1810             : 
    1811        3034 :         close_file_free(NULL, &fsp, close_type);
    1812        3034 :         return true;
    1813             : }
    1814             : 
    1815             : /****************************************************************************
    1816             :  Close all open files for a connection.
    1817             : ****************************************************************************/
    1818             : 
    1819             : struct file_close_conn_state {
    1820             :         struct connection_struct *conn;
    1821             :         enum file_close_type close_type;
    1822             :         bool fsp_left_behind;
    1823             : };
    1824             : 
    1825        1714 : static struct files_struct *file_close_conn_fn(
    1826             :         struct files_struct *fsp,
    1827             :         void *private_data)
    1828             : {
    1829        1714 :         struct file_close_conn_state *state = private_data;
    1830           8 :         bool did_close;
    1831             : 
    1832        1714 :         if (fsp->conn != state->conn) {
    1833        1274 :                 return NULL;
    1834             :         }
    1835             : 
    1836         438 :         if (fsp->op != NULL && fsp->op->global->durable) {
    1837             :                 /*
    1838             :                  * A tree disconnect closes a durable handle
    1839             :                  */
    1840           4 :                 fsp->op->global->durable = false;
    1841             :         }
    1842             : 
    1843         438 :         did_close = close_file_in_loop(fsp, state->close_type);
    1844         438 :         if (!did_close) {
    1845           0 :                 state->fsp_left_behind = true;
    1846             :         }
    1847             : 
    1848         432 :         return NULL;
    1849             : }
    1850             : 
    1851       48683 : void file_close_conn(connection_struct *conn, enum file_close_type close_type)
    1852             : {
    1853       48683 :         struct file_close_conn_state state = { .conn = conn,
    1854             :                                                .close_type = close_type };
    1855             : 
    1856       48683 :         files_forall(conn->sconn, file_close_conn_fn, &state);
    1857             : 
    1858       48683 :         if (state.fsp_left_behind) {
    1859           0 :                 state.fsp_left_behind = false;
    1860           0 :                 files_forall(conn->sconn, file_close_conn_fn, &state);
    1861           0 :                 SMB_ASSERT(!state.fsp_left_behind);
    1862             :         }
    1863       48683 : }
    1864             : 
    1865             : /****************************************************************************
    1866             :  Initialise file structures.
    1867             : ****************************************************************************/
    1868             : 
    1869             : static int files_max_open_fds;
    1870             : 
    1871       31581 : bool file_init_global(void)
    1872             : {
    1873       31581 :         int request_max = lp_max_open_files();
    1874         842 :         int real_lim;
    1875         842 :         int real_max;
    1876             : 
    1877       31581 :         if (files_max_open_fds != 0) {
    1878       30721 :                 return true;
    1879             :         }
    1880             : 
    1881             :         /*
    1882             :          * Set the max_open files to be the requested
    1883             :          * max plus a fudgefactor to allow for the extra
    1884             :          * fd's we need such as log files etc...
    1885             :          */
    1886          18 :         real_lim = set_maxfiles(request_max + MAX_OPEN_FUDGEFACTOR);
    1887             : 
    1888          18 :         real_max = real_lim - MAX_OPEN_FUDGEFACTOR;
    1889             : 
    1890          18 :         if (real_max + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536) {
    1891           0 :                 real_max = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
    1892             :         }
    1893             : 
    1894          18 :         if (real_max != request_max) {
    1895           0 :                 DEBUG(1, ("file_init_global: Information only: requested %d "
    1896             :                           "open files, %d are available.\n",
    1897             :                           request_max, real_max));
    1898             :         }
    1899             : 
    1900          18 :         SMB_ASSERT(real_max > 100);
    1901             : 
    1902          18 :         files_max_open_fds = real_max;
    1903          18 :         return true;
    1904             : }
    1905             : 
    1906       31581 : bool file_init(struct smbd_server_connection *sconn)
    1907             : {
    1908         842 :         bool ok;
    1909             : 
    1910       31581 :         ok = file_init_global();
    1911       31581 :         if (!ok) {
    1912           0 :                 return false;
    1913             :         }
    1914             : 
    1915       31581 :         sconn->real_max_open_files = files_max_open_fds;
    1916             : 
    1917       31581 :         return true;
    1918             : }
    1919             : 
    1920             : /****************************************************************************
    1921             :  Close files open by a specified vuid.
    1922             : ****************************************************************************/
    1923             : 
    1924             : struct file_close_user_state {
    1925             :         uint64_t vuid;
    1926             :         bool fsp_left_behind;
    1927             : };
    1928             : 
    1929        2892 : static struct files_struct *file_close_user_fn(
    1930             :         struct files_struct *fsp,
    1931             :         void *private_data)
    1932             : {
    1933        2892 :         struct file_close_user_state *state = private_data;
    1934         290 :         bool did_close;
    1935             : 
    1936        2892 :         if (fsp->vuid != state->vuid) {
    1937         222 :                 return NULL;
    1938             :         }
    1939             : 
    1940        2668 :         did_close = close_file_in_loop(fsp, SHUTDOWN_CLOSE);
    1941        2668 :         if (!did_close) {
    1942          72 :                 state->fsp_left_behind = true;
    1943             :         }
    1944             : 
    1945        2380 :         return NULL;
    1946             : }
    1947             : 
    1948       32243 : void file_close_user(struct smbd_server_connection *sconn, uint64_t vuid)
    1949             : {
    1950       32243 :         struct file_close_user_state state = { .vuid = vuid };
    1951             : 
    1952       32243 :         files_forall(sconn, file_close_user_fn, &state);
    1953             : 
    1954       32243 :         if (state.fsp_left_behind) {
    1955          36 :                 state.fsp_left_behind = false;
    1956          36 :                 files_forall(sconn, file_close_user_fn, &state);
    1957          36 :                 SMB_ASSERT(!state.fsp_left_behind);
    1958             :         }
    1959       32243 : }
    1960             : 
    1961             : /*
    1962             :  * Walk the files table until "fn" returns non-NULL
    1963             :  */
    1964             : 
    1965      233602 : struct files_struct *files_forall(
    1966             :         struct smbd_server_connection *sconn,
    1967             :         struct files_struct *(*fn)(struct files_struct *fsp,
    1968             :                                    void *private_data),
    1969             :         void *private_data)
    1970             : {
    1971        1889 :         struct files_struct *fsp, *next;
    1972             : 
    1973      458835 :         for (fsp = sconn->files; fsp; fsp = next) {
    1974         373 :                 struct files_struct *ret;
    1975      227214 :                 next = fsp->next;
    1976      227214 :                 ret = fn(fsp, private_data);
    1977      227214 :                 if (ret != NULL) {
    1978        1981 :                         return ret;
    1979             :                 }
    1980             :         }
    1981      229746 :         return NULL;
    1982             : }
    1983             : 
    1984             : /****************************************************************************
    1985             :  Find a fsp given a file descriptor.
    1986             : ****************************************************************************/
    1987             : 
    1988           4 : files_struct *file_find_fd(struct smbd_server_connection *sconn, int fd)
    1989             : {
    1990           4 :         int count=0;
    1991           0 :         files_struct *fsp;
    1992             : 
    1993           5 :         for (fsp=sconn->files; fsp; fsp=fsp->next,count++) {
    1994           5 :                 if (fsp_get_pathref_fd(fsp) == fd) {
    1995           4 :                         if (count > 10) {
    1996           0 :                                 DLIST_PROMOTE(sconn->files, fsp);
    1997             :                         }
    1998           4 :                         return fsp;
    1999             :                 }
    2000             :         }
    2001             : 
    2002           0 :         return NULL;
    2003             : }
    2004             : 
    2005             : /****************************************************************************
    2006             :  Find a fsp given a device, inode and file_id.
    2007             : ****************************************************************************/
    2008             : 
    2009       14638 : files_struct *file_find_dif(struct smbd_server_connection *sconn,
    2010             :                             struct file_id id, unsigned long gen_id)
    2011             : {
    2012       14638 :         int count=0;
    2013          71 :         files_struct *fsp;
    2014             : 
    2015       14638 :         if (gen_id == 0) {
    2016           0 :                 return NULL;
    2017             :         }
    2018             : 
    2019      202921 :         for (fsp = sconn->files; fsp; fsp = fsp->next,count++) {
    2020             :                 /*
    2021             :                  * We can have a fsp->fh->fd == -1 here as it could be a stat
    2022             :                  * open.
    2023             :                  */
    2024      202921 :                 if (!file_id_equal(&fsp->file_id, &id)) {
    2025       17109 :                         continue;
    2026             :                 }
    2027      185812 :                 if (!fsp->fsp_flags.is_fsa) {
    2028       14655 :                         continue;
    2029             :                 }
    2030      171157 :                 if (fh_get_gen_id(fsp->fh) != gen_id) {
    2031      156519 :                         continue;
    2032             :                 }
    2033       14638 :                 if (count > 10) {
    2034        4646 :                         DLIST_PROMOTE(sconn->files, fsp);
    2035             :                 }
    2036       14567 :                 return fsp;
    2037             :         }
    2038             : 
    2039           0 :         return NULL;
    2040             : }
    2041             : 
    2042             : /****************************************************************************
    2043             :  Find the first fsp given a device and inode.
    2044             :  We use a singleton cache here to speed up searching from getfilepathinfo
    2045             :  calls.
    2046             : ****************************************************************************/
    2047             : 
    2048       12409 : files_struct *file_find_di_first(struct smbd_server_connection *sconn,
    2049             :                                  struct file_id id,
    2050             :                                  bool need_fsa)
    2051             : {
    2052         301 :         files_struct *fsp;
    2053             : 
    2054       12409 :         if (file_id_equal(&sconn->fsp_fi_cache.id, &id)) {
    2055             :                 /* Positive or negative cache hit. */
    2056           0 :                 return sconn->fsp_fi_cache.fsp;
    2057             :         }
    2058             : 
    2059       12409 :         sconn->fsp_fi_cache.id = id;
    2060             : 
    2061       40269 :         for (fsp=sconn->files;fsp;fsp=fsp->next) {
    2062       31623 :                 if (need_fsa && !fsp->fsp_flags.is_fsa) {
    2063       21228 :                         continue;
    2064             :                 }
    2065       10395 :                 if (file_id_equal(&fsp->file_id, &id)) {
    2066             :                         /* Setup positive cache. */
    2067        3763 :                         sconn->fsp_fi_cache.fsp = fsp;
    2068        3763 :                         return fsp;
    2069             :                 }
    2070             :         }
    2071             : 
    2072             :         /* Setup negative cache. */
    2073        8646 :         sconn->fsp_fi_cache.fsp = NULL;
    2074        8646 :         return NULL;
    2075             : }
    2076             : 
    2077             : /****************************************************************************
    2078             :  Find the next fsp having the same device and inode.
    2079             : ****************************************************************************/
    2080             : 
    2081        2069 : files_struct *file_find_di_next(files_struct *start_fsp,
    2082             :                                 bool need_fsa)
    2083             : {
    2084          21 :         files_struct *fsp;
    2085             : 
    2086        2891 :         for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
    2087         977 :                 if (need_fsa && !fsp->fsp_flags.is_fsa) {
    2088           0 :                         continue;
    2089             :                 }
    2090         977 :                 if (file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
    2091         155 :                         return fsp;
    2092             :                 }
    2093             :         }
    2094             : 
    2095        1898 :         return NULL;
    2096             : }
    2097             : 
    2098           4 : struct files_struct *file_find_one_fsp_from_lease_key(
    2099             :         struct smbd_server_connection *sconn,
    2100             :         const struct smb2_lease_key *lease_key)
    2101             : {
    2102           0 :         struct files_struct *fsp;
    2103             : 
    2104           6 :         for (fsp = sconn->files; fsp; fsp=fsp->next) {
    2105           6 :                 if ((fsp->lease != NULL) &&
    2106           4 :                     (fsp->lease->lease.lease_key.data[0] ==
    2107           4 :                      lease_key->data[0]) &&
    2108           4 :                     (fsp->lease->lease.lease_key.data[1] ==
    2109           4 :                      lease_key->data[1])) {
    2110           4 :                         return fsp;
    2111             :                 }
    2112             :         }
    2113           0 :         return NULL;
    2114             : }
    2115             : 
    2116             : /****************************************************************************
    2117             :  Find any fsp open with a pathname below that of an already open path.
    2118             : ****************************************************************************/
    2119             : 
    2120          19 : bool file_find_subpath(files_struct *dir_fsp)
    2121             : {
    2122           5 :         files_struct *fsp;
    2123           5 :         size_t dlen;
    2124          19 :         char *d_fullname = NULL;
    2125             : 
    2126          19 :         d_fullname = talloc_asprintf(talloc_tos(), "%s/%s",
    2127          19 :                                      dir_fsp->conn->connectpath,
    2128          19 :                                      dir_fsp->fsp_name->base_name);
    2129             : 
    2130          19 :         if (!d_fullname) {
    2131           0 :                 return false;
    2132             :         }
    2133             : 
    2134          19 :         dlen = strlen(d_fullname);
    2135             : 
    2136          86 :         for (fsp=dir_fsp->conn->sconn->files; fsp; fsp=fsp->next) {
    2137          20 :                 char *d1_fullname;
    2138             : 
    2139          70 :                 if (fsp == dir_fsp) {
    2140          19 :                         continue;
    2141             :                 }
    2142             : 
    2143          51 :                 d1_fullname = talloc_asprintf(talloc_tos(),
    2144             :                                         "%s/%s",
    2145          51 :                                         fsp->conn->connectpath,
    2146          51 :                                         fsp->fsp_name->base_name);
    2147             : 
    2148             :                 /*
    2149             :                  * If the open file has a path that is a longer
    2150             :                  * component, then it's a subpath.
    2151             :                  */
    2152          51 :                 if (strnequal(d_fullname, d1_fullname, dlen) &&
    2153          15 :                                 (d1_fullname[dlen] == '/')) {
    2154           3 :                         TALLOC_FREE(d1_fullname);
    2155           3 :                         TALLOC_FREE(d_fullname);
    2156           3 :                         return true;
    2157             :                 }
    2158          53 :                 TALLOC_FREE(d1_fullname);
    2159             :         }
    2160             : 
    2161          16 :         TALLOC_FREE(d_fullname);
    2162          16 :         return false;
    2163             : }
    2164             : 
    2165             : /****************************************************************************
    2166             :  Free up a fsp.
    2167             : ****************************************************************************/
    2168             : 
    2169     6284180 : static void fsp_free(files_struct *fsp)
    2170             : {
    2171     6284180 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
    2172             : 
    2173     6284180 :         if (fsp == sconn->fsp_fi_cache.fsp) {
    2174         517 :                 ZERO_STRUCT(sconn->fsp_fi_cache);
    2175             :         }
    2176             : 
    2177     6284180 :         DLIST_REMOVE(sconn->files, fsp);
    2178     6284180 :         SMB_ASSERT(sconn->num_files > 0);
    2179     6284180 :         sconn->num_files--;
    2180             : 
    2181     6284180 :         TALLOC_FREE(fsp->fake_file_handle);
    2182             : 
    2183     6284180 :         if (fh_get_refcount(fsp->fh) == 1) {
    2184     6284067 :                 TALLOC_FREE(fsp->fh);
    2185             :         } else {
    2186         113 :                 size_t new_refcount = fh_get_refcount(fsp->fh) - 1;
    2187         113 :                 fh_set_refcount(fsp->fh, new_refcount);
    2188             :         }
    2189             : 
    2190     6284180 :         if (fsp->lease != NULL) {
    2191        1024 :                 if (fsp->lease->ref_count == 1) {
    2192         812 :                         TALLOC_FREE(fsp->lease);
    2193             :                 } else {
    2194         212 :                         fsp->lease->ref_count--;
    2195             :                 }
    2196             :         }
    2197             : 
    2198     6284180 :         fsp->conn->num_files_open--;
    2199             : 
    2200     6284180 :         if (fsp->fsp_name != NULL &&
    2201     6134406 :             fsp->fsp_name->fsp_link != NULL)
    2202             :         {
    2203             :                 /*
    2204             :                  * Free fsp_link of fsp->fsp_name. To do this in the correct
    2205             :                  * talloc destructor order we have to do it here. The
    2206             :                  * talloc_free() of the link should set the fsp pointer to NULL.
    2207             :                  */
    2208     6074979 :                 TALLOC_FREE(fsp->fsp_name->fsp_link);
    2209     6074979 :                 SMB_ASSERT(fsp->fsp_name->fsp == NULL);
    2210             :         }
    2211             : 
    2212             :         /* this is paranoia, just in case someone tries to reuse the
    2213             :            information */
    2214     6284180 :         ZERO_STRUCTP(fsp);
    2215             : 
    2216             :         /* fsp->fsp_name is a talloc child and is free'd automatically. */
    2217     6284180 :         TALLOC_FREE(fsp);
    2218     6284180 : }
    2219             : 
    2220             : /*
    2221             :  * Rundown of all smb-related sub-structures of an fsp
    2222             :  */
    2223     6869320 : void fsp_unbind_smb(struct smb_request *req, files_struct *fsp)
    2224             : {
    2225     6869320 :         if (fsp == fsp->conn->cwd_fsp) {
    2226           0 :                 return;
    2227             :         }
    2228             : 
    2229     6869320 :         if (fsp->notify) {
    2230        1866 :                 size_t len = fsp_fullbasepath(fsp, NULL, 0);
    2231        1866 :                 char fullpath[len+1];
    2232             : 
    2233        1866 :                 fsp_fullbasepath(fsp, fullpath, sizeof(fullpath));
    2234             : 
    2235        1866 :                 notify_remove(fsp->conn->sconn->notify_ctx, fsp, fullpath);
    2236        1866 :                 TALLOC_FREE(fsp->notify);
    2237             :         }
    2238             : 
    2239             :         /* Ensure this event will never fire. */
    2240     6869320 :         TALLOC_FREE(fsp->update_write_time_event);
    2241             : 
    2242     6869320 :         if (fsp->op != NULL) {
    2243      568091 :                 fsp->op->compat = NULL;
    2244             :         }
    2245     6869320 :         TALLOC_FREE(fsp->op);
    2246             : 
    2247     6869320 :         if ((req != NULL) && (fsp == req->chain_fsp)) {
    2248      556306 :                 req->chain_fsp = NULL;
    2249             :         }
    2250             : 
    2251             :         /*
    2252             :          * Clear all possible chained fsp
    2253             :          * pointers in the SMB2 request queue.
    2254             :          */
    2255     6869320 :         remove_smb2_chained_fsp(fsp);
    2256             : }
    2257             : 
    2258     6284180 : void file_free(struct smb_request *req, files_struct *fsp)
    2259             : {
    2260     6284180 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
    2261     6284180 :         uint64_t fnum = fsp->fnum;
    2262             : 
    2263     6284180 :         fsp_unbind_smb(req, fsp);
    2264             : 
    2265             :         /* Drop all remaining extensions. */
    2266     6284180 :         vfs_remove_all_fsp_extensions(fsp);
    2267             : 
    2268     6284180 :         fsp_free(fsp);
    2269             : 
    2270     6284180 :         DBG_INFO("freed files structure %"PRIu64" (%zu used)\n",
    2271             :                  fnum,
    2272             :                  sconn->num_files);
    2273     6284180 : }
    2274             : 
    2275             : /****************************************************************************
    2276             :  Get an fsp from a packet given a 16 bit fnum.
    2277             : ****************************************************************************/
    2278             : 
    2279      212009 : files_struct *file_fsp(struct smb_request *req, uint16_t fid)
    2280             : {
    2281        1269 :         struct smbXsrv_open *op;
    2282        1269 :         NTSTATUS status;
    2283      212009 :         NTTIME now = 0;
    2284        1269 :         files_struct *fsp;
    2285             : 
    2286      212009 :         if (req == NULL) {
    2287             :                 /*
    2288             :                  * We should never get here. req==NULL could in theory
    2289             :                  * only happen from internal opens with a non-zero
    2290             :                  * root_dir_fid. Internal opens just don't do that, at
    2291             :                  * least they are not supposed to do so. And if they
    2292             :                  * start to do so, they better fake up a smb_request
    2293             :                  * from which we get the right smbd_server_conn. While
    2294             :                  * this should never happen, let's return NULL here.
    2295             :                  */
    2296           0 :                 return NULL;
    2297             :         }
    2298             : 
    2299      212009 :         if (req->chain_fsp != NULL) {
    2300         102 :                 if (req->chain_fsp->fsp_flags.closing) {
    2301           0 :                         return NULL;
    2302             :                 }
    2303         102 :                 return req->chain_fsp;
    2304             :         }
    2305             : 
    2306      211907 :         if (req->xconn == NULL) {
    2307           0 :                 return NULL;
    2308             :         }
    2309             : 
    2310      211907 :         now = timeval_to_nttime(&req->request_time);
    2311             : 
    2312      211907 :         status = smb1srv_open_lookup(req->xconn,
    2313             :                                      fid, now, &op);
    2314      211907 :         if (!NT_STATUS_IS_OK(status)) {
    2315        2688 :                 return NULL;
    2316             :         }
    2317             : 
    2318      209160 :         fsp = op->compat;
    2319      209160 :         if (fsp == NULL) {
    2320           0 :                 return NULL;
    2321             :         }
    2322             : 
    2323      209160 :         if (fsp->fsp_flags.closing) {
    2324           0 :                 return NULL;
    2325             :         }
    2326             : 
    2327      209160 :         req->chain_fsp = fsp;
    2328      209160 :         fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTE_INVALID;
    2329      209160 :         return fsp;
    2330             : }
    2331             : 
    2332      841147 : struct files_struct *file_fsp_get(struct smbd_smb2_request *smb2req,
    2333             :                                   uint64_t persistent_id,
    2334             :                                   uint64_t volatile_id)
    2335             : {
    2336        7957 :         struct smbXsrv_open *op;
    2337        7957 :         NTSTATUS status;
    2338      841147 :         NTTIME now = 0;
    2339        7957 :         struct files_struct *fsp;
    2340             : 
    2341      841147 :         now = timeval_to_nttime(&smb2req->request_time);
    2342             : 
    2343      841147 :         status = smb2srv_open_lookup(smb2req->xconn,
    2344             :                                      persistent_id, volatile_id,
    2345             :                                      now, &op);
    2346      841147 :         if (!NT_STATUS_IS_OK(status)) {
    2347       14019 :                 return NULL;
    2348             :         }
    2349             : 
    2350      827128 :         fsp = op->compat;
    2351      827128 :         if (fsp == NULL) {
    2352           0 :                 return NULL;
    2353             :         }
    2354             : 
    2355      827128 :         if (smb2req->tcon == NULL) {
    2356           0 :                 return NULL;
    2357             :         }
    2358             : 
    2359      827128 :         if (smb2req->tcon->compat != fsp->conn) {
    2360           4 :                 return NULL;
    2361             :         }
    2362             : 
    2363      827124 :         if (smb2req->session == NULL) {
    2364           0 :                 return NULL;
    2365             :         }
    2366             : 
    2367      827124 :         if (smb2req->session->global->session_wire_id != fsp->vuid) {
    2368           0 :                 return NULL;
    2369             :         }
    2370             : 
    2371      827124 :         if (fsp->fsp_flags.closing) {
    2372           0 :                 return NULL;
    2373             :         }
    2374             : 
    2375      827124 :         fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTE_INVALID;
    2376             : 
    2377      827124 :         return fsp;
    2378             : }
    2379             : 
    2380     1668169 : struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
    2381             :                                    uint64_t persistent_id,
    2382             :                                    uint64_t volatile_id)
    2383             : {
    2384       15912 :         struct files_struct *fsp;
    2385             : 
    2386     1668169 :         if (smb2req->compat_chain_fsp != NULL) {
    2387      827022 :                 if (smb2req->compat_chain_fsp->fsp_flags.closing) {
    2388           0 :                         return NULL;
    2389             :                 }
    2390      827022 :                 smb2req->compat_chain_fsp->fsp_name->st.cached_dos_attributes =
    2391             :                         FILE_ATTRIBUTE_INVALID;
    2392      827022 :                 return smb2req->compat_chain_fsp;
    2393             :         }
    2394             : 
    2395      841147 :         fsp = file_fsp_get(smb2req, persistent_id, volatile_id);
    2396      841147 :         if (fsp == NULL) {
    2397       14023 :                 return NULL;
    2398             :         }
    2399             : 
    2400      827124 :         smb2req->compat_chain_fsp = fsp;
    2401      827124 :         return fsp;
    2402             : }
    2403             : 
    2404             : /****************************************************************************
    2405             :  Duplicate the file handle part for a DOS or FCB open.
    2406             : ****************************************************************************/
    2407             : 
    2408         113 : NTSTATUS dup_file_fsp(
    2409             :         files_struct *from,
    2410             :         uint32_t access_mask,
    2411             :         files_struct *to)
    2412             : {
    2413           1 :         size_t new_refcount;
    2414             : 
    2415             :         /* this can never happen for print files */
    2416         113 :         SMB_ASSERT(from->print_file == NULL);
    2417             : 
    2418         113 :         TALLOC_FREE(to->fh);
    2419             : 
    2420         113 :         to->fh = from->fh;
    2421         113 :         new_refcount = fh_get_refcount(to->fh) + 1;
    2422         113 :         fh_set_refcount(to->fh, new_refcount);
    2423             : 
    2424         113 :         to->file_id = from->file_id;
    2425         113 :         to->initial_allocation_size = from->initial_allocation_size;
    2426         113 :         to->file_pid = from->file_pid;
    2427         113 :         to->vuid = from->vuid;
    2428         113 :         to->open_time = from->open_time;
    2429         113 :         to->access_mask = access_mask;
    2430         113 :         to->oplock_type = from->oplock_type;
    2431         113 :         to->fsp_flags.can_lock = from->fsp_flags.can_lock;
    2432         113 :         to->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
    2433         114 :         to->fsp_flags.can_write =
    2434         225 :                 CAN_WRITE(from->conn) &&
    2435         113 :                 ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
    2436         113 :         if (from->fsp_name->twrp != 0) {
    2437           0 :                 to->fsp_flags.can_write = false;
    2438             :         }
    2439         113 :         to->fsp_flags.modified = from->fsp_flags.modified;
    2440         113 :         to->fsp_flags.is_directory = from->fsp_flags.is_directory;
    2441         113 :         to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind;
    2442         113 :         to->fsp_flags.is_fsa = from->fsp_flags.is_fsa;
    2443         113 :         to->fsp_flags.is_pathref = from->fsp_flags.is_pathref;
    2444         113 :         to->fsp_flags.have_proc_fds = from->fsp_flags.have_proc_fds;
    2445         113 :         to->fsp_flags.is_dirfsp = from->fsp_flags.is_dirfsp;
    2446             : 
    2447         113 :         return fsp_set_smb_fname(to, from->fsp_name);
    2448             : }
    2449             : 
    2450             : /**
    2451             :  * Return a jenkins hash of a pathname on a connection.
    2452             :  */
    2453             : 
    2454     6216579 : NTSTATUS file_name_hash(connection_struct *conn,
    2455             :                         const char *name, uint32_t *p_name_hash)
    2456             : {
    2457       32963 :         char tmpbuf[PATH_MAX];
    2458       32963 :         char *fullpath, *to_free;
    2459       32963 :         ssize_t len;
    2460       32963 :         TDB_DATA key;
    2461             : 
    2462             :         /* Set the hash of the full pathname. */
    2463             : 
    2464     6216579 :         if (name[0] == '/') {
    2465     1446281 :                 strlcpy(tmpbuf, name, sizeof(tmpbuf));
    2466     1446281 :                 fullpath = tmpbuf;
    2467     1446281 :                 len = strlen(fullpath);
    2468     1446281 :                 to_free = NULL;
    2469             :         } else {
    2470     4770298 :                 len = full_path_tos(conn->connectpath,
    2471             :                                     name,
    2472             :                                     tmpbuf,
    2473             :                                     sizeof(tmpbuf),
    2474             :                                     &fullpath,
    2475             :                                     &to_free);
    2476             :         }
    2477     6216579 :         if (len == -1) {
    2478           0 :                 return NT_STATUS_NO_MEMORY;
    2479             :         }
    2480     6216579 :         key = (TDB_DATA) { .dptr = (uint8_t *)fullpath, .dsize = len+1 };
    2481     6216579 :         *p_name_hash = tdb_jenkins_hash(&key);
    2482             : 
    2483     6216579 :         DEBUG(10,("file_name_hash: %s hash 0x%x\n",
    2484             :                   fullpath,
    2485             :                 (unsigned int)*p_name_hash ));
    2486             : 
    2487     6216579 :         TALLOC_FREE(to_free);
    2488     6216579 :         return NT_STATUS_OK;
    2489             : }
    2490             : 
    2491     6080547 : static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
    2492             :                                      struct smb_filename **_smb_fname)
    2493             : {
    2494     6080547 :         TALLOC_CTX *frame = talloc_stackframe();
    2495     6080547 :         struct smb_filename *smb_fname_new = talloc_move(fsp, _smb_fname);
    2496     6080547 :         const char *name_str = NULL;
    2497     6080547 :         uint32_t name_hash = 0;
    2498       32313 :         NTSTATUS status;
    2499             : 
    2500     6080547 :         name_str = smb_fname_str_dbg(smb_fname_new);
    2501     6080547 :         if (name_str == NULL) {
    2502           0 :                 TALLOC_FREE(frame);
    2503           0 :                 return NT_STATUS_NO_MEMORY;
    2504             :         }
    2505             : 
    2506     6080547 :         status = file_name_hash(fsp->conn,
    2507             :                                 name_str,
    2508             :                                 &name_hash);
    2509     6080547 :         TALLOC_FREE(frame);
    2510     6080547 :         name_str = NULL;
    2511     6080547 :         if (!NT_STATUS_IS_OK(status)) {
    2512           0 :                 return status;
    2513             :         }
    2514             : 
    2515     6080547 :         status = fsp_smb_fname_link(fsp,
    2516             :                                     &smb_fname_new->fsp_link,
    2517             :                                     &smb_fname_new->fsp);
    2518     6080547 :         if (!NT_STATUS_IS_OK(status)) {
    2519           0 :                 return status;
    2520             :         }
    2521             : 
    2522     6080547 :         fsp->name_hash = name_hash;
    2523     6080547 :         fsp->fsp_name = smb_fname_new;
    2524     6080547 :         fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTE_INVALID;
    2525     6080547 :         *_smb_fname = NULL;
    2526     6080547 :         return NT_STATUS_OK;
    2527             : }
    2528             : 
    2529             : /**
    2530             :  * The only way that the fsp->fsp_name field should ever be set.
    2531             :  */
    2532     1100910 : NTSTATUS fsp_set_smb_fname(struct files_struct *fsp,
    2533             :                            const struct smb_filename *smb_fname_in)
    2534             : {
    2535     1100910 :         struct smb_filename *smb_fname_old = fsp->fsp_name;
    2536     1100910 :         struct smb_filename *smb_fname_new = NULL;
    2537       11069 :         NTSTATUS status;
    2538             : 
    2539     1100910 :         smb_fname_new = cp_smb_filename(fsp, smb_fname_in);
    2540     1100910 :         if (smb_fname_new == NULL) {
    2541           0 :                 return NT_STATUS_NO_MEMORY;
    2542             :         }
    2543             : 
    2544     1100910 :         status = fsp_attach_smb_fname(fsp, &smb_fname_new);
    2545     1100910 :         if (!NT_STATUS_IS_OK(status)) {
    2546           0 :                 TALLOC_FREE(smb_fname_new);
    2547           0 :                 return status;
    2548             :         }
    2549             : 
    2550     1100910 :         if (smb_fname_old != NULL) {
    2551      589216 :                 smb_fname_fsp_unlink(smb_fname_old);
    2552      589216 :                 TALLOC_FREE(smb_fname_old);
    2553             :         }
    2554             : 
    2555     1100910 :         return NT_STATUS_OK;
    2556             : }
    2557             : 
    2558        7466 : size_t fsp_fullbasepath(struct files_struct *fsp, char *buf, size_t buflen)
    2559             : {
    2560        7466 :         int len = 0;
    2561             : 
    2562        7466 :         if (buf == NULL) {
    2563             :                 /*
    2564             :                  * susv4 allows buf==NULL if buflen==0 for snprintf.
    2565             :                  */
    2566        3734 :                 SMB_ASSERT(buflen == 0);
    2567             :         }
    2568             : 
    2569        7466 :         if (ISDOT(fsp->fsp_name->base_name)) {
    2570         384 :                 len = snprintf(buf, buflen, "%s", fsp->conn->connectpath);
    2571             :         } else {
    2572        7082 :                 len = snprintf(buf,
    2573             :                                buflen,
    2574             :                                "%s/%s",
    2575        7082 :                                fsp->conn->connectpath,
    2576        7082 :                                fsp->fsp_name->base_name);
    2577             :         }
    2578        7466 :         SMB_ASSERT(len > 0);
    2579             : 
    2580        7466 :         return len;
    2581             : }
    2582             : 
    2583     4950134 : void fsp_set_base_fsp(struct files_struct *fsp, struct files_struct *base_fsp)
    2584             : {
    2585     4950134 :         SMB_ASSERT(fsp->stream_fsp == NULL);
    2586     4950134 :         if (base_fsp != NULL) {
    2587       15505 :                 SMB_ASSERT(base_fsp->base_fsp == NULL);
    2588       15505 :                 SMB_ASSERT(base_fsp->stream_fsp == NULL);
    2589             :         }
    2590             : 
    2591     4950134 :         if (fsp->base_fsp != NULL) {
    2592        7430 :                 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
    2593        7430 :                 fsp->base_fsp->stream_fsp = NULL;
    2594             :         }
    2595             : 
    2596     4950134 :         fsp->base_fsp = base_fsp;
    2597     4950134 :         if (fsp->base_fsp != NULL) {
    2598       15505 :                 fsp->base_fsp->stream_fsp = fsp;
    2599             :         }
    2600     4950134 : }
    2601             : 
    2602    21904850 : bool fsp_is_alternate_stream(const struct files_struct *fsp)
    2603             : {
    2604    21904850 :         return (fsp->base_fsp != NULL);
    2605             : }
    2606             : 
    2607     4605437 : struct files_struct *metadata_fsp(struct files_struct *fsp)
    2608             : {
    2609     4605437 :         if (fsp_is_alternate_stream(fsp)) {
    2610       22005 :                 return fsp->base_fsp;
    2611             :         }
    2612     4573975 :         return fsp;
    2613             : }
    2614             : 
    2615      414092 : static bool fsp_generic_ask_sharemode(struct files_struct *fsp)
    2616             : {
    2617      414092 :         if (fsp == NULL) {
    2618           0 :                 return false;
    2619             :         }
    2620             : 
    2621      414092 :         if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
    2622             :                 /* Always use filesystem for UNIX mtime query. */
    2623        1530 :                 return false;
    2624             :         }
    2625             : 
    2626      410990 :         return true;
    2627             : }
    2628             : 
    2629       29958 : bool fsp_search_ask_sharemode(struct files_struct *fsp)
    2630             : {
    2631       29958 :         if (!fsp_generic_ask_sharemode(fsp)) {
    2632          24 :                 return false;
    2633             :         }
    2634             : 
    2635       29934 :         return lp_smbd_search_ask_sharemode(SNUM(fsp->conn));
    2636             : }
    2637             : 
    2638      384134 : bool fsp_getinfo_ask_sharemode(struct files_struct *fsp)
    2639             : {
    2640      384134 :         if (!fsp_generic_ask_sharemode(fsp)) {
    2641        1506 :                 return false;
    2642             :         }
    2643             : 
    2644      382628 :         return lp_smbd_getinfo_ask_sharemode(SNUM(fsp->conn));
    2645             : }

Generated by: LCOV version 1.14