LCOV - code coverage report
Current view: top level - source3/smbd - file_access.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 47 68 69.1 %
Date: 2021-09-23 10:06:22 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             : 
      27             : #undef  DBGC_CLASS
      28             : #define DBGC_CLASS DBGC_ACLS
      29             : 
      30             : /****************************************************************************
      31             :  Actually emulate the in-kernel access checking for delete access. We need
      32             :  this to successfully return ACCESS_DENIED on a file open for delete access.
      33             : ****************************************************************************/
      34             : 
      35        1546 : bool can_delete_file_in_directory(connection_struct *conn,
      36             :                         struct files_struct *dirfsp,
      37             :                         const struct smb_filename *smb_fname)
      38             : {
      39        1546 :         struct smb_filename *smb_fname_parent = NULL;
      40             :         bool ret;
      41             :         NTSTATUS status;
      42             : 
      43        1546 :         if (!CAN_WRITE(conn)) {
      44           0 :                 return False;
      45             :         }
      46             : 
      47        1546 :         if (!lp_acl_check_permissions(SNUM(conn))) {
      48             :                 /* This option means don't check. */
      49           0 :                 return true;
      50             :         }
      51             : 
      52        1546 :         if (get_current_uid(conn) == (uid_t)0) {
      53             :                 /* I'm sorry sir, I didn't know you were root... */
      54           0 :                 return true;
      55             :         }
      56             : 
      57        1546 :         if (dirfsp != conn->cwd_fsp) {
      58        1530 :                 smb_fname_parent = dirfsp->fsp_name;
      59             :         } else {
      60          16 :                 struct smb_filename *atname = NULL;
      61             :                 /*
      62             :                  * Get a pathref on the parent.
      63             :                  */
      64          16 :                 status = parent_pathref(talloc_tos(),
      65             :                                         conn->cwd_fsp,
      66             :                                         smb_fname,
      67             :                                         &smb_fname_parent,
      68             :                                         &atname);
      69          16 :                 if (!NT_STATUS_IS_OK(status)) {
      70           0 :                         return false;
      71             :                 }
      72             :         }
      73             : 
      74        1546 :         SMB_ASSERT(VALID_STAT(smb_fname_parent->st));
      75             : 
      76             :         /* fast paths first */
      77             : 
      78        1546 :         if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) {
      79           0 :                 ret = false;
      80           0 :                 goto out;
      81             :         }
      82             : 
      83             : #ifdef S_ISVTX
      84             :         /* sticky bit means delete only by owner of file or by root or
      85             :          * by owner of directory. */
      86        1546 :         if (smb_fname_parent->st.st_ex_mode & S_ISVTX) {
      87           0 :                 if (!VALID_STAT(smb_fname->st)) {
      88             :                         /* If the file doesn't already exist then
      89             :                          * yes we'll be able to delete it. */
      90           0 :                         ret = true;
      91           0 :                         goto out;
      92             :                 }
      93             : 
      94             :                 /*
      95             :                  * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com>
      96             :                  * for bug #3348. Don't assume owning sticky bit
      97             :                  * directory means write access allowed.
      98             :                  * Fail to delete if we're not the owner of the file,
      99             :                  * or the owner of the directory as we have no possible
     100             :                  * chance of deleting. Otherwise, go on and check the ACL.
     101             :                  */
     102           0 :                 if ((get_current_uid(conn) !=
     103           0 :                         smb_fname_parent->st.st_ex_uid) &&
     104           0 :                     (get_current_uid(conn) != smb_fname->st.st_ex_uid)) {
     105           0 :                         DEBUG(10,("can_delete_file_in_directory: not "
     106             :                                   "owner of file %s or directory %s",
     107             :                                   smb_fname_str_dbg(smb_fname),
     108             :                                   smb_fname_str_dbg(smb_fname_parent)));
     109           0 :                         ret = false;
     110           0 :                         goto out;
     111             :                 }
     112             :         }
     113             : #endif
     114             : 
     115             :         /* now for ACL checks */
     116             : 
     117             :         /*
     118             :          * There's two ways to get the permission to delete a file: First by
     119             :          * having the DELETE bit on the file itself and second if that does
     120             :          * not help, by the DELETE_CHILD bit on the containing directory.
     121             :          *
     122             :          * Here we only check the directory permissions, we will
     123             :          * check the file DELETE permission separately.
     124             :          */
     125             : 
     126        1546 :         ret = NT_STATUS_IS_OK(smbd_check_access_rights_fsp(
     127             :                                 conn->cwd_fsp,
     128             :                                 smb_fname_parent->fsp,
     129             :                                 false,
     130             :                                 FILE_DELETE_CHILD));
     131        1546 :  out:
     132        1546 :         if (smb_fname_parent != dirfsp->fsp_name) {
     133          16 :                 TALLOC_FREE(smb_fname_parent);
     134             :         }
     135        1546 :         return ret;
     136             : }
     137             : 
     138             : /****************************************************************************
     139             :  Userspace check for write access to fsp.
     140             : ****************************************************************************/
     141             : 
     142         835 : bool can_write_to_fsp(struct files_struct *fsp)
     143             : {
     144         835 :         return NT_STATUS_IS_OK(smbd_check_access_rights_fsp(
     145             :                                                         fsp->conn->cwd_fsp,
     146             :                                                         fsp,
     147             :                                                         false,
     148             :                                                         FILE_WRITE_DATA));
     149             : }
     150             : 
     151             : /****************************************************************************
     152             :  Check for an existing default Windows ACL on a directory fsp.
     153             : ****************************************************************************/
     154             : 
     155      154359 : bool directory_has_default_acl_fsp(struct files_struct *fsp)
     156             : {
     157      154359 :         struct security_descriptor *secdesc = NULL;
     158             :         unsigned int i;
     159             :         NTSTATUS status;
     160             : 
     161      154359 :         status = SMB_VFS_FGET_NT_ACL(fsp,
     162             :                                 SECINFO_DACL,
     163             :                                 talloc_tos(),
     164             :                                 &secdesc);
     165             : 
     166      279790 :         if (!NT_STATUS_IS_OK(status) ||
     167      279790 :             secdesc == NULL ||
     168      154359 :             secdesc->dacl == NULL)
     169             :         {
     170           0 :                 TALLOC_FREE(secdesc);
     171           0 :                 return false;
     172             :         }
     173             : 
     174      337119 :         for (i = 0; i < secdesc->dacl->num_aces; i++) {
     175      336341 :                 struct security_ace *psa = &secdesc->dacl->aces[i];
     176             : 
     177      336341 :                 if (psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
     178             :                                 SEC_ACE_FLAG_CONTAINER_INHERIT))
     179             :                 {
     180      153309 :                         TALLOC_FREE(secdesc);
     181      153309 :                         return true;
     182             :                 }
     183             :         }
     184        1050 :         TALLOC_FREE(secdesc);
     185        1050 :         return false;
     186             : }
     187             : 
     188             : /****************************************************************************
     189             :  Check if setting delete on close is allowed on this fsp.
     190             : ****************************************************************************/
     191             : 
     192      184247 : NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode)
     193             : {
     194             :         /*
     195             :          * Only allow delete on close for writable files.
     196             :          */
     197             : 
     198      184399 :         if ((dosmode & FILE_ATTRIBUTE_READONLY) &&
     199         168 :             !lp_delete_readonly(SNUM(fsp->conn))) {
     200         160 :                 DEBUG(10,("can_set_delete_on_close: file %s delete on close "
     201             :                           "flag set but file attribute is readonly.\n",
     202             :                           fsp_str_dbg(fsp)));
     203         160 :                 return NT_STATUS_CANNOT_DELETE;
     204             :         }
     205             : 
     206             :         /*
     207             :          * Only allow delete on close for writable shares.
     208             :          */
     209             : 
     210      184087 :         if (!CAN_WRITE(fsp->conn)) {
     211           0 :                 DEBUG(10,("can_set_delete_on_close: file %s delete on "
     212             :                           "close flag set but write access denied on share.\n",
     213             :                           fsp_str_dbg(fsp)));
     214           0 :                 return NT_STATUS_ACCESS_DENIED;
     215             :         }
     216             : 
     217             :         /*
     218             :          * Only allow delete on close for files/directories opened with delete
     219             :          * intent.
     220             :          */
     221             : 
     222      184087 :         if (!(fsp->access_mask & DELETE_ACCESS)) {
     223          18 :                 DEBUG(10,("can_set_delete_on_close: file %s delete on "
     224             :                           "close flag set but delete access denied.\n",
     225             :                           fsp_str_dbg(fsp)));
     226          18 :                 return NT_STATUS_ACCESS_DENIED;
     227             :         }
     228             : 
     229             :         /* Don't allow delete on close for non-empty directories. */
     230      184069 :         if (fsp->fsp_flags.is_directory) {
     231       10372 :                 SMB_ASSERT(!is_ntfs_stream_smb_fname(fsp->fsp_name));
     232             : 
     233             :                 /* Or the root of a share. */
     234       10372 :                 if (ISDOT(fsp->fsp_name->base_name)) {
     235           0 :                         DEBUG(10,("can_set_delete_on_close: can't set delete on "
     236             :                                   "close for the root of a share.\n"));
     237           0 :                         return NT_STATUS_ACCESS_DENIED;
     238             :                 }
     239             : 
     240       10372 :                 return can_delete_directory_fsp(fsp);
     241             :         }
     242             : 
     243      173697 :         return NT_STATUS_OK;
     244             : }

Generated by: LCOV version 1.13