s3-includes: only include system/filesys.h when needed.
[ira/wip.git] / source3 / smbd / file_access.c
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
26 #undef  DBGC_CLASS
27 #define DBGC_CLASS DBGC_ACLS
28
29 /**
30  * Security descriptor / NT Token level access check function.
31  */
32 bool can_access_file_acl(struct connection_struct *conn,
33                          const struct smb_filename *smb_fname,
34                          uint32_t access_mask)
35 {
36         NTSTATUS status;
37         uint32_t access_granted;
38         struct security_descriptor *secdesc = NULL;
39         bool ret;
40
41         if (get_current_uid(conn) == (uid_t)0) {
42                 /* I'm sorry sir, I didn't know you were root... */
43                 return true;
44         }
45
46         status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
47                                     (SECINFO_OWNER |
48                                      SECINFO_GROUP |
49                                      SECINFO_DACL),
50                                     &secdesc);
51         if (!NT_STATUS_IS_OK(status)) {
52                 DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status)));
53                 ret = false;
54                 goto out;
55         }
56
57         status = se_access_check(secdesc, get_current_nttok(conn),
58                                  access_mask, &access_granted);
59         ret = NT_STATUS_IS_OK(status);
60
61         if (DEBUGLEVEL >= 10) {
62                 DEBUG(10,("can_access_file_acl for file %s "
63                         "access_mask 0x%x, access_granted 0x%x "
64                         "access %s\n",
65                         smb_fname_str_dbg(smb_fname),
66                         (unsigned int)access_mask,
67                         (unsigned int)access_granted,
68                         ret ? "ALLOWED" : "DENIED" ));
69                 NDR_PRINT_DEBUG(security_descriptor, secdesc);
70         }
71  out:
72         TALLOC_FREE(secdesc);
73         return ret;
74 }
75
76 /****************************************************************************
77  Actually emulate the in-kernel access checking for delete access. We need
78  this to successfully return ACCESS_DENIED on a file open for delete access.
79 ****************************************************************************/
80
81 bool can_delete_file_in_directory(connection_struct *conn,
82                                   struct smb_filename *smb_fname)
83 {
84         TALLOC_CTX *ctx = talloc_tos();
85         char *dname = NULL;
86         struct smb_filename *smb_fname_parent = NULL;
87         NTSTATUS status;
88         bool ret;
89
90         if (!CAN_WRITE(conn)) {
91                 return False;
92         }
93
94         /* Get the parent directory permission mask and owners. */
95         if (!parent_dirname(ctx, smb_fname->base_name, &dname, NULL)) {
96                 return False;
97         }
98
99         status = create_synthetic_smb_fname(ctx, dname, NULL, NULL,
100                                             &smb_fname_parent);
101         if (!NT_STATUS_IS_OK(status)) {
102                 ret = false;
103                 goto out;
104         }
105
106         if(SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
107                 ret = false;
108                 goto out;
109         }
110
111         /* fast paths first */
112
113         if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) {
114                 ret = false;
115                 goto out;
116         }
117         if (get_current_uid(conn) == (uid_t)0) {
118                 /* I'm sorry sir, I didn't know you were root... */
119                 ret = true;
120                 goto out;
121         }
122
123 #ifdef S_ISVTX
124         /* sticky bit means delete only by owner of file or by root or
125          * by owner of directory. */
126         if (smb_fname_parent->st.st_ex_mode & S_ISVTX) {
127                 if(SMB_VFS_STAT(conn, smb_fname) != 0) {
128                         if (errno == ENOENT) {
129                                 /* If the file doesn't already exist then
130                                  * yes we'll be able to delete it. */
131                                 ret = true;
132                                 goto out;
133                         }
134                         DEBUG(10,("can_delete_file_in_directory: can't "
135                                   "stat file %s (%s)",
136                                   smb_fname_str_dbg(smb_fname),
137                                   strerror(errno) ));
138                         ret = false;
139                         goto out;
140                 }
141
142                 /*
143                  * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com>
144                  * for bug #3348. Don't assume owning sticky bit
145                  * directory means write access allowed.
146                  * Fail to delete if we're not the owner of the file,
147                  * or the owner of the directory as we have no possible
148                  * chance of deleting. Otherwise, go on and check the ACL.
149                  */
150                 if ((get_current_uid(conn) !=
151                         smb_fname_parent->st.st_ex_uid) &&
152                     (get_current_uid(conn) != smb_fname->st.st_ex_uid)) {
153                         DEBUG(10,("can_delete_file_in_directory: not "
154                                   "owner of file %s or directory %s",
155                                   smb_fname_str_dbg(smb_fname),
156                                   smb_fname_str_dbg(smb_fname_parent)));
157                         ret = false;
158                         goto out;
159                 }
160         }
161 #endif
162
163         /* now for ACL checks */
164
165         /*
166          * There's two ways to get the permission to delete a file: First by
167          * having the DELETE bit on the file itself and second if that does
168          * not help, by the DELETE_CHILD bit on the containing directory.
169          *
170          * Here we only check the directory permissions, we will
171          * check the file DELETE permission separately.
172          */
173
174         ret = can_access_file_acl(conn, smb_fname_parent, FILE_DELETE_CHILD);
175  out:
176         TALLOC_FREE(dname);
177         TALLOC_FREE(smb_fname_parent);
178         return ret;
179 }
180
181 /****************************************************************************
182  Actually emulate the in-kernel access checking for read/write access. We need
183  this to successfully check for ability to write for dos filetimes.
184  Note this doesn't take into account share write permissions.
185 ****************************************************************************/
186
187 bool can_access_file_data(connection_struct *conn,
188                           const struct smb_filename *smb_fname,
189                           uint32 access_mask)
190 {
191         if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) {
192                 return False;
193         }
194         access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA);
195
196         /* some fast paths first */
197
198         DEBUG(10,("can_access_file_data: requesting 0x%x on file %s\n",
199                   (unsigned int)access_mask, smb_fname_str_dbg(smb_fname)));
200
201         if (get_current_uid(conn) == (uid_t)0) {
202                 /* I'm sorry sir, I didn't know you were root... */
203                 return True;
204         }
205
206         SMB_ASSERT(VALID_STAT(smb_fname->st));
207
208         /* Check primary owner access. */
209         if (get_current_uid(conn) == smb_fname->st.st_ex_uid) {
210                 switch (access_mask) {
211                         case FILE_READ_DATA:
212                                 return (smb_fname->st.st_ex_mode & S_IRUSR) ?
213                                     True : False;
214
215                         case FILE_WRITE_DATA:
216                                 return (smb_fname->st.st_ex_mode & S_IWUSR) ?
217                                     True : False;
218
219                         default: /* FILE_READ_DATA|FILE_WRITE_DATA */
220
221                                 if ((smb_fname->st.st_ex_mode &
222                                         (S_IWUSR|S_IRUSR)) ==
223                                     (S_IWUSR|S_IRUSR)) {
224                                         return True;
225                                 } else {
226                                         return False;
227                                 }
228                 }
229         }
230
231         /* now for ACL checks */
232
233         return can_access_file_acl(conn, smb_fname, access_mask);
234 }
235
236 /****************************************************************************
237  Userspace check for write access.
238  Note this doesn't take into account share write permissions.
239 ****************************************************************************/
240
241 bool can_write_to_file(connection_struct *conn,
242                        const struct smb_filename *smb_fname)
243 {
244         return can_access_file_data(conn, smb_fname, FILE_WRITE_DATA);
245 }
246
247 /****************************************************************************
248  Check for an existing default Windows ACL on a directory.
249 ****************************************************************************/
250
251 bool directory_has_default_acl(connection_struct *conn, const char *fname)
252 {
253         /* returns talloced off tos. */
254         struct security_descriptor *secdesc = NULL;
255         unsigned int i;
256         NTSTATUS status = SMB_VFS_GET_NT_ACL(conn, fname,
257                                 SECINFO_DACL, &secdesc);
258
259         if (!NT_STATUS_IS_OK(status) || secdesc == NULL) {
260                 return false;
261         }
262
263         for (i = 0; i < secdesc->dacl->num_aces; i++) {
264                 struct security_ace *psa = &secdesc->dacl->aces[i];
265                 if (psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
266                                 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
267                         TALLOC_FREE(secdesc);
268                         return true;
269                 }
270         }
271         TALLOC_FREE(secdesc);
272         return false;
273 }