LCOV - code coverage report
Current view: top level - source3/smbd - files.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 1013 1195 84.8 %
Date: 2024-02-28 12:06:22 Functions: 61 61 100.0 %

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

Generated by: LCOV version 1.14