/src/samba/source3/smbd/file_access.c
Line | Count | Source |
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 | 0 | #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 | | bool can_delete_file_in_directory(connection_struct *conn, |
37 | | struct files_struct *dirfsp, |
38 | | const struct smb_filename *smb_fname) |
39 | 0 | { |
40 | 0 | struct smb_filename *smb_fname_parent = NULL; |
41 | 0 | bool ret; |
42 | 0 | NTSTATUS status; |
43 | |
|
44 | 0 | if (!CAN_WRITE(conn)) { |
45 | 0 | return False; |
46 | 0 | } |
47 | | |
48 | 0 | if (!lp_acl_check_permissions(SNUM(conn))) { |
49 | | /* This option means don't check. */ |
50 | 0 | return true; |
51 | 0 | } |
52 | | |
53 | 0 | 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 | 0 | } |
57 | | |
58 | 0 | if (dirfsp != conn->cwd_fsp) { |
59 | 0 | smb_fname_parent = dirfsp->fsp_name; |
60 | 0 | } else { |
61 | 0 | struct smb_filename *atname = NULL; |
62 | | /* |
63 | | * Get a pathref on the parent. |
64 | | */ |
65 | 0 | status = parent_pathref(talloc_tos(), |
66 | 0 | conn->cwd_fsp, |
67 | 0 | smb_fname, |
68 | 0 | &smb_fname_parent, |
69 | 0 | &atname); |
70 | 0 | if (!NT_STATUS_IS_OK(status)) { |
71 | 0 | return false; |
72 | 0 | } |
73 | 0 | } |
74 | | |
75 | 0 | SMB_ASSERT(VALID_STAT(smb_fname_parent->st)); |
76 | | |
77 | | /* fast paths first */ |
78 | | |
79 | 0 | if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) { |
80 | 0 | ret = false; |
81 | 0 | goto out; |
82 | 0 | } |
83 | | |
84 | 0 | #ifdef S_ISVTX |
85 | | /* sticky bit means delete only by owner of file or by root or |
86 | | * by owner of directory. */ |
87 | 0 | 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 | 0 | } |
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 | DBG_DEBUG("not owner of file %s or directory %s\n", |
107 | 0 | smb_fname_str_dbg(smb_fname), |
108 | 0 | smb_fname_str_dbg(smb_fname_parent)); |
109 | 0 | ret = false; |
110 | 0 | goto out; |
111 | 0 | } |
112 | 0 | } |
113 | 0 | #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 | 0 | ret = NT_STATUS_IS_OK(smbd_check_access_rights_fsp( |
127 | 0 | conn->cwd_fsp, |
128 | 0 | smb_fname_parent->fsp, |
129 | 0 | false, |
130 | 0 | FILE_DELETE_CHILD)); |
131 | 0 | out: |
132 | 0 | if (smb_fname_parent != dirfsp->fsp_name) { |
133 | 0 | TALLOC_FREE(smb_fname_parent); |
134 | 0 | } |
135 | 0 | return ret; |
136 | 0 | } |
137 | | |
138 | | /**************************************************************************** |
139 | | Userspace check for write access to fsp. |
140 | | ****************************************************************************/ |
141 | | |
142 | | bool can_write_to_fsp(struct files_struct *fsp) |
143 | 0 | { |
144 | 0 | return NT_STATUS_IS_OK(smbd_check_access_rights_fsp( |
145 | 0 | fsp->conn->cwd_fsp, |
146 | 0 | fsp, |
147 | 0 | false, |
148 | 0 | FILE_WRITE_DATA)); |
149 | 0 | } |
150 | | |
151 | | /**************************************************************************** |
152 | | Check for an existing default Windows ACL on a directory fsp. |
153 | | ****************************************************************************/ |
154 | | |
155 | | bool directory_has_default_acl_fsp(struct files_struct *fsp) |
156 | 0 | { |
157 | 0 | struct security_descriptor *secdesc = NULL; |
158 | 0 | unsigned int i; |
159 | 0 | NTSTATUS status; |
160 | |
|
161 | 0 | status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp), |
162 | 0 | SECINFO_DACL, |
163 | 0 | talloc_tos(), |
164 | 0 | &secdesc); |
165 | |
|
166 | 0 | if (!NT_STATUS_IS_OK(status) || |
167 | 0 | secdesc == NULL || |
168 | 0 | secdesc->dacl == NULL) |
169 | 0 | { |
170 | 0 | TALLOC_FREE(secdesc); |
171 | 0 | return false; |
172 | 0 | } |
173 | | |
174 | 0 | for (i = 0; i < secdesc->dacl->num_aces; i++) { |
175 | 0 | struct security_ace *psa = &secdesc->dacl->aces[i]; |
176 | |
|
177 | 0 | if (psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT| |
178 | 0 | SEC_ACE_FLAG_CONTAINER_INHERIT)) |
179 | 0 | { |
180 | 0 | TALLOC_FREE(secdesc); |
181 | 0 | return true; |
182 | 0 | } |
183 | 0 | } |
184 | 0 | TALLOC_FREE(secdesc); |
185 | 0 | return false; |
186 | 0 | } |
187 | | |
188 | | /**************************************************************************** |
189 | | Check if setting delete on close is allowed on this fsp. |
190 | | ****************************************************************************/ |
191 | | |
192 | | NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode) |
193 | 0 | { |
194 | 0 | NTSTATUS status; |
195 | | /* |
196 | | * Only allow delete on close for writable files. |
197 | | */ |
198 | |
|
199 | 0 | 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 | 0 | "flag set but file attribute is readonly.\n", |
203 | 0 | fsp_str_dbg(fsp))); |
204 | 0 | return NT_STATUS_CANNOT_DELETE; |
205 | 0 | } |
206 | | |
207 | | /* |
208 | | * Only allow delete on close for writable shares. |
209 | | */ |
210 | | |
211 | 0 | if (!CAN_WRITE(fsp->conn)) { |
212 | 0 | DEBUG(10,("can_set_delete_on_close: file %s delete on " |
213 | 0 | "close flag set but write access denied on share.\n", |
214 | 0 | fsp_str_dbg(fsp))); |
215 | 0 | return NT_STATUS_ACCESS_DENIED; |
216 | 0 | } |
217 | | |
218 | | /* |
219 | | * Only allow delete on close for files/directories opened with delete |
220 | | * intent. |
221 | | */ |
222 | | |
223 | 0 | status = check_any_access_fsp(fsp, DELETE_ACCESS); |
224 | 0 | if (!NT_STATUS_IS_OK(status)) { |
225 | 0 | DBG_DEBUG("file %s delete on " |
226 | 0 | "close flag set but delete access denied.\n", |
227 | 0 | fsp_str_dbg(fsp)); |
228 | 0 | return status; |
229 | 0 | } |
230 | | |
231 | | /* Don't allow delete on close for non-empty directories. */ |
232 | 0 | if (fsp->fsp_flags.is_directory) { |
233 | 0 | SMB_ASSERT(!fsp_is_alternate_stream(fsp)); |
234 | | |
235 | | /* Or the root of a share. */ |
236 | 0 | if (ISDOT(fsp->fsp_name->base_name)) { |
237 | 0 | DEBUG(10,("can_set_delete_on_close: can't set delete on " |
238 | 0 | "close for the root of a share.\n")); |
239 | 0 | return NT_STATUS_ACCESS_DENIED; |
240 | 0 | } |
241 | | |
242 | 0 | return can_delete_directory_fsp(fsp); |
243 | 0 | } |
244 | | |
245 | 0 | return NT_STATUS_OK; |
246 | 0 | } |