LCOV - code coverage report
Current view: top level - source3/smbd - file_access.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 55 74 74.3 %
Date: 2024-04-21 15:09:00 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Check access to files based on security descriptors.
       4             :    Copyright (C) Jeremy Allison 2005-2006.
       5             :    Copyright (C) Michael Adam 2007.
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "system/filesys.h"
      23             : #include "../libcli/security/security.h"
      24             : #include "../librpc/gen_ndr/ndr_security.h"
      25             : #include "smbd/smbd.h"
      26             : #include "source3/smbd/dir.h"
      27             : 
      28             : #undef  DBGC_CLASS
      29             : #define DBGC_CLASS DBGC_ACLS
      30             : 
      31             : /****************************************************************************
      32             :  Actually emulate the in-kernel access checking for delete access. We need
      33             :  this to successfully return ACCESS_DENIED on a file open for delete access.
      34             : ****************************************************************************/
      35             : 
      36        1836 : bool can_delete_file_in_directory(connection_struct *conn,
      37             :                         struct files_struct *dirfsp,
      38             :                         const struct smb_filename *smb_fname)
      39             : {
      40        1836 :         struct smb_filename *smb_fname_parent = NULL;
      41           6 :         bool ret;
      42           6 :         NTSTATUS status;
      43             : 
      44        1836 :         if (!CAN_WRITE(conn)) {
      45           0 :                 return False;
      46             :         }
      47             : 
      48        1836 :         if (!lp_acl_check_permissions(SNUM(conn))) {
      49             :                 /* This option means don't check. */
      50           0 :                 return true;
      51             :         }
      52             : 
      53        1836 :         if (get_current_uid(conn) == (uid_t)0) {
      54             :                 /* I'm sorry sir, I didn't know you were root... */
      55           0 :                 return true;
      56             :         }
      57             : 
      58        1836 :         if (dirfsp != conn->cwd_fsp) {
      59        1536 :                 smb_fname_parent = dirfsp->fsp_name;
      60             :         } else {
      61         300 :                 struct smb_filename *atname = NULL;
      62             :                 /*
      63             :                  * Get a pathref on the parent.
      64             :                  */
      65         300 :                 status = parent_pathref(talloc_tos(),
      66             :                                         conn->cwd_fsp,
      67             :                                         smb_fname,
      68             :                                         &smb_fname_parent,
      69             :                                         &atname);
      70         300 :                 if (!NT_STATUS_IS_OK(status)) {
      71           0 :                         return false;
      72             :                 }
      73             :         }
      74             : 
      75        1836 :         SMB_ASSERT(VALID_STAT(smb_fname_parent->st));
      76             : 
      77             :         /* fast paths first */
      78             : 
      79        1836 :         if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) {
      80           0 :                 ret = false;
      81           0 :                 goto out;
      82             :         }
      83             : 
      84             : #ifdef S_ISVTX
      85             :         /* sticky bit means delete only by owner of file or by root or
      86             :          * by owner of directory. */
      87        1836 :         if (smb_fname_parent->st.st_ex_mode & S_ISVTX) {
      88           0 :                 if (!VALID_STAT(smb_fname->st)) {
      89             :                         /* If the file doesn't already exist then
      90             :                          * yes we'll be able to delete it. */
      91           0 :                         ret = true;
      92           0 :                         goto out;
      93             :                 }
      94             : 
      95             :                 /*
      96             :                  * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com>
      97             :                  * for bug #3348. Don't assume owning sticky bit
      98             :                  * directory means write access allowed.
      99             :                  * Fail to delete if we're not the owner of the file,
     100             :                  * or the owner of the directory as we have no possible
     101             :                  * chance of deleting. Otherwise, go on and check the ACL.
     102             :                  */
     103           0 :                 if ((get_current_uid(conn) !=
     104           0 :                         smb_fname_parent->st.st_ex_uid) &&
     105           0 :                     (get_current_uid(conn) != smb_fname->st.st_ex_uid)) {
     106           0 :                         DEBUG(10,("can_delete_file_in_directory: not "
     107             :                                   "owner of file %s or directory %s\n",
     108             :                                   smb_fname_str_dbg(smb_fname),
     109             :                                   smb_fname_str_dbg(smb_fname_parent)));
     110           0 :                         ret = false;
     111           0 :                         goto out;
     112             :                 }
     113             :         }
     114             : #endif
     115             : 
     116             :         /* now for ACL checks */
     117             : 
     118             :         /*
     119             :          * There's two ways to get the permission to delete a file: First by
     120             :          * having the DELETE bit on the file itself and second if that does
     121             :          * not help, by the DELETE_CHILD bit on the containing directory.
     122             :          *
     123             :          * Here we only check the directory permissions, we will
     124             :          * check the file DELETE permission separately.
     125             :          */
     126             : 
     127        1836 :         ret = NT_STATUS_IS_OK(smbd_check_access_rights_fsp(
     128             :                                 conn->cwd_fsp,
     129             :                                 smb_fname_parent->fsp,
     130             :                                 false,
     131             :                                 FILE_DELETE_CHILD));
     132        1836 :  out:
     133        1836 :         if (smb_fname_parent != dirfsp->fsp_name) {
     134         300 :                 TALLOC_FREE(smb_fname_parent);
     135             :         }
     136        1830 :         return ret;
     137             : }
     138             : 
     139             : /****************************************************************************
     140             :  Userspace check for write access to fsp.
     141             : ****************************************************************************/
     142             : 
     143        1258 : bool can_write_to_fsp(struct files_struct *fsp)
     144             : {
     145        1258 :         return NT_STATUS_IS_OK(smbd_check_access_rights_fsp(
     146             :                                                         fsp->conn->cwd_fsp,
     147             :                                                         fsp,
     148             :                                                         false,
     149             :                                                         FILE_WRITE_DATA));
     150             : }
     151             : 
     152             : /****************************************************************************
     153             :  Check for an existing default Windows ACL on a directory fsp.
     154             : ****************************************************************************/
     155             : 
     156      159948 : bool directory_has_default_acl_fsp(struct files_struct *fsp)
     157             : {
     158      159948 :         struct security_descriptor *secdesc = NULL;
     159         416 :         unsigned int i;
     160         416 :         NTSTATUS status;
     161             : 
     162      159948 :         status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
     163             :                                 SECINFO_DACL,
     164             :                                 talloc_tos(),
     165             :                                 &secdesc);
     166             : 
     167      159948 :         if (!NT_STATUS_IS_OK(status) ||
     168      159948 :             secdesc == NULL ||
     169      159948 :             secdesc->dacl == NULL)
     170             :         {
     171           0 :                 TALLOC_FREE(secdesc);
     172           0 :                 return false;
     173             :         }
     174             : 
     175      349613 :         for (i = 0; i < secdesc->dacl->num_aces; i++) {
     176      348555 :                 struct security_ace *psa = &secdesc->dacl->aces[i];
     177             : 
     178      348555 :                 if (psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
     179             :                                 SEC_ACE_FLAG_CONTAINER_INHERIT))
     180             :                 {
     181      158890 :                         TALLOC_FREE(secdesc);
     182      158890 :                         return true;
     183             :                 }
     184             :         }
     185        1058 :         TALLOC_FREE(secdesc);
     186        1058 :         return false;
     187             : }
     188             : 
     189             : /****************************************************************************
     190             :  Check if setting delete on close is allowed on this fsp.
     191             : ****************************************************************************/
     192             : 
     193      170603 : NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode)
     194             : {
     195         351 :         NTSTATUS status;
     196             :         /*
     197             :          * Only allow delete on close for writable files.
     198             :          */
     199             : 
     200      170605 :         if ((dosmode & FILE_ATTRIBUTE_READONLY) &&
     201          58 :             !lp_delete_readonly(SNUM(fsp->conn))) {
     202          50 :                 DEBUG(10,("can_set_delete_on_close: file %s delete on close "
     203             :                           "flag set but file attribute is readonly.\n",
     204             :                           fsp_str_dbg(fsp)));
     205          50 :                 return NT_STATUS_CANNOT_DELETE;
     206             :         }
     207             : 
     208             :         /*
     209             :          * Only allow delete on close for writable shares.
     210             :          */
     211             : 
     212      170553 :         if (!CAN_WRITE(fsp->conn)) {
     213           0 :                 DEBUG(10,("can_set_delete_on_close: file %s delete on "
     214             :                           "close flag set but write access denied on share.\n",
     215             :                           fsp_str_dbg(fsp)));
     216           0 :                 return NT_STATUS_ACCESS_DENIED;
     217             :         }
     218             : 
     219             :         /*
     220             :          * Only allow delete on close for files/directories opened with delete
     221             :          * intent.
     222             :          */
     223             : 
     224      170553 :         status = check_any_access_fsp(fsp, DELETE_ACCESS);
     225      170553 :         if (!NT_STATUS_IS_OK(status)) {
     226          19 :                 DBG_DEBUG("file %s delete on "
     227             :                           "close flag set but delete access denied.\n",
     228             :                           fsp_str_dbg(fsp));
     229          19 :                 return status;
     230             :         }
     231             : 
     232             :         /* Don't allow delete on close for non-empty directories. */
     233      170534 :         if (fsp->fsp_flags.is_directory) {
     234       11290 :                 SMB_ASSERT(!fsp_is_alternate_stream(fsp));
     235             : 
     236             :                 /* Or the root of a share. */
     237       11290 :                 if (ISDOT(fsp->fsp_name->base_name)) {
     238          42 :                         DEBUG(10,("can_set_delete_on_close: can't set delete on "
     239             :                                   "close for the root of a share.\n"));
     240          42 :                         return NT_STATUS_ACCESS_DENIED;
     241             :                 }
     242             : 
     243       11248 :                 return can_delete_directory_fsp(fsp);
     244             :         }
     245             : 
     246      159244 :         return NT_STATUS_OK;
     247             : }

Generated by: LCOV version 1.14