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