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 10 : bool can_delete_file_in_directory(connection_struct *conn, 36 : struct files_struct *dirfsp, 37 : const struct smb_filename *smb_fname) 38 : { 39 10 : struct smb_filename *smb_fname_parent = NULL; 40 : bool ret; 41 : NTSTATUS status; 42 : 43 10 : if (!CAN_WRITE(conn)) { 44 0 : return False; 45 : } 46 : 47 10 : if (!lp_acl_check_permissions(SNUM(conn))) { 48 : /* This option means don't check. */ 49 0 : return true; 50 : } 51 : 52 10 : 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 10 : if (dirfsp != conn->cwd_fsp) { 58 8 : smb_fname_parent = dirfsp->fsp_name; 59 : } else { 60 2 : struct smb_filename *atname = NULL; 61 : /* 62 : * Get a pathref on the parent. 63 : */ 64 2 : status = parent_pathref(talloc_tos(), 65 : conn->cwd_fsp, 66 : smb_fname, 67 : &smb_fname_parent, 68 : &atname); 69 2 : if (!NT_STATUS_IS_OK(status)) { 70 0 : return false; 71 : } 72 : } 73 : 74 10 : SMB_ASSERT(VALID_STAT(smb_fname_parent->st)); 75 : 76 : /* fast paths first */ 77 : 78 10 : 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 10 : 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 10 : 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 10 : out: 132 10 : if (smb_fname_parent != dirfsp->fsp_name) { 133 2 : TALLOC_FREE(smb_fname_parent); 134 : } 135 10 : return ret; 136 : } 137 : 138 : /**************************************************************************** 139 : Userspace check for write access to fsp. 140 : ****************************************************************************/ 141 : 142 0 : bool can_write_to_fsp(struct files_struct *fsp) 143 : { 144 0 : 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 1448 : bool directory_has_default_acl_fsp(struct files_struct *fsp) 156 : { 157 1448 : struct security_descriptor *secdesc = NULL; 158 : unsigned int i; 159 : NTSTATUS status; 160 : 161 1448 : status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp), 162 : SECINFO_DACL, 163 : talloc_tos(), 164 : &secdesc); 165 : 166 1448 : if (!NT_STATUS_IS_OK(status) || 167 1448 : secdesc == NULL || 168 1448 : secdesc->dacl == NULL) 169 : { 170 0 : TALLOC_FREE(secdesc); 171 0 : return false; 172 : } 173 : 174 2542 : for (i = 0; i < secdesc->dacl->num_aces; i++) { 175 2538 : struct security_ace *psa = &secdesc->dacl->aces[i]; 176 : 177 2538 : if (psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT| 178 : SEC_ACE_FLAG_CONTAINER_INHERIT)) 179 : { 180 1444 : TALLOC_FREE(secdesc); 181 1444 : return true; 182 : } 183 : } 184 4 : TALLOC_FREE(secdesc); 185 4 : return false; 186 : } 187 : 188 : /**************************************************************************** 189 : Check if setting delete on close is allowed on this fsp. 190 : ****************************************************************************/ 191 : 192 1374 : NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode) 193 : { 194 : NTSTATUS status; 195 : /* 196 : * Only allow delete on close for writable files. 197 : */ 198 : 199 1374 : if ((dosmode & FILE_ATTRIBUTE_READONLY) && 200 0 : !lp_delete_readonly(SNUM(fsp->conn))) { 201 0 : DEBUG(10,("can_set_delete_on_close: file %s delete on close " 202 : "flag set but file attribute is readonly.\n", 203 : fsp_str_dbg(fsp))); 204 0 : return NT_STATUS_CANNOT_DELETE; 205 : } 206 : 207 : /* 208 : * Only allow delete on close for writable shares. 209 : */ 210 : 211 1374 : if (!CAN_WRITE(fsp->conn)) { 212 0 : DEBUG(10,("can_set_delete_on_close: file %s delete on " 213 : "close flag set but write access denied on share.\n", 214 : fsp_str_dbg(fsp))); 215 0 : return NT_STATUS_ACCESS_DENIED; 216 : } 217 : 218 : /* 219 : * Only allow delete on close for files/directories opened with delete 220 : * intent. 221 : */ 222 : 223 1374 : status = check_any_access_fsp(fsp, DELETE_ACCESS); 224 1374 : if (!NT_STATUS_IS_OK(status)) { 225 0 : DBG_DEBUG("file %s delete on " 226 : "close flag set but delete access denied.\n", 227 : fsp_str_dbg(fsp)); 228 0 : return status; 229 : } 230 : 231 : /* Don't allow delete on close for non-empty directories. */ 232 1374 : if (fsp->fsp_flags.is_directory) { 233 814 : SMB_ASSERT(!fsp_is_alternate_stream(fsp)); 234 : 235 : /* Or the root of a share. */ 236 814 : if (ISDOT(fsp->fsp_name->base_name)) { 237 0 : DEBUG(10,("can_set_delete_on_close: can't set delete on " 238 : "close for the root of a share.\n")); 239 0 : return NT_STATUS_ACCESS_DENIED; 240 : } 241 : 242 814 : return can_delete_directory_fsp(fsp); 243 : } 244 : 245 560 : return NT_STATUS_OK; 246 : }