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