r4314: added ACL checking on unlink
[kai/samba-autobuild/.git] / source4 / ntvfs / posix / pvfs_acl.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - ACL support
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "system/filesys.h"
26 #include "vfs_posix.h"
27 #include "librpc/gen_ndr/ndr_xattr.h"
28
29
30 /*
31   map a single access_mask from generic to specific bits for files/dirs
32 */
33 static uint32_t pvfs_translate_mask(uint32_t access_mask)
34 {
35         if (access_mask & SEC_MASK_GENERIC) {
36                 if (access_mask & SEC_GENERIC_READ)    access_mask |= SEC_RIGHTS_FILE_READ;
37                 if (access_mask & SEC_GENERIC_WRITE)   access_mask |= SEC_RIGHTS_FILE_WRITE;
38                 if (access_mask & SEC_GENERIC_EXECUTE) access_mask |= SEC_RIGHTS_FILE_EXECUTE;
39                 if (access_mask & SEC_GENERIC_ALL)     access_mask |= SEC_RIGHTS_FILE_ALL;
40                 access_mask &= ~SEC_MASK_GENERIC;
41         }
42         return access_mask;
43 }
44
45
46 /*
47   map any generic access bits in the given acl
48   this relies on the fact that the mappings for files and directories
49   are the same
50 */
51 static void pvfs_translate_generic_bits(struct security_acl *acl)
52 {
53         unsigned i;
54
55         for (i=0;i<acl->num_aces;i++) {
56                 struct security_ace *ace = &acl->aces[i];
57                 ace->access_mask = pvfs_translate_mask(ace->access_mask);
58         }
59 }
60
61
62 /*
63   setup a default ACL for a file
64 */
65 static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs,
66                                  struct smbsrv_request *req,
67                                  struct pvfs_filename *name, int fd, 
68                                  struct xattr_NTACL *acl)
69 {
70         struct security_descriptor *sd;
71         NTSTATUS status;
72         struct security_ace aces[4];
73         mode_t mode;
74         struct dom_sid *sid;
75         int i;
76
77         sd = security_descriptor_initialise(req);
78         if (sd == NULL) {
79                 return NT_STATUS_NO_MEMORY;
80         }
81
82         status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
83         if (!NT_STATUS_IS_OK(status)) {
84                 return status;
85         }
86         status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
87         if (!NT_STATUS_IS_OK(status)) {
88                 return status;
89         }
90
91         sd->type |= SEC_DESC_DACL_PRESENT;
92
93         /*
94           we provide 4 ACEs
95             - Administrator
96             - Owner
97             - Group
98             - Everyone
99          */
100         aces[0].access_mask = SEC_RIGHTS_FILE_ALL;
101         aces[1].access_mask = 0;
102         aces[2].access_mask = 0;
103         aces[3].access_mask = 0;
104
105         mode = name->st.st_mode;
106
107         if (mode & S_IRUSR) {
108                 aces[1].access_mask |= 
109                         SEC_FILE_READ_DATA | 
110                         SEC_FILE_READ_EA |
111                         SEC_FILE_READ_ATTRIBUTE |
112                         SEC_FILE_EXECUTE |
113                         SEC_STD_SYNCHRONIZE |
114                         SEC_STD_READ_CONTROL;
115         }
116         if (mode & S_IWUSR) {
117                 aces[1].access_mask |= 
118                         SEC_FILE_WRITE_DATA | 
119                         SEC_FILE_APPEND_DATA |
120                         SEC_FILE_WRITE_EA |
121                         SEC_FILE_WRITE_ATTRIBUTE |
122                         SEC_STD_DELETE;
123         }
124
125         if (mode & S_IRGRP) {
126                 aces[2].access_mask |= 
127                         SEC_FILE_READ_DATA | 
128                         SEC_FILE_READ_EA |
129                         SEC_FILE_READ_ATTRIBUTE |
130                         SEC_FILE_EXECUTE |
131                         SEC_STD_SYNCHRONIZE |
132                         SEC_STD_READ_CONTROL;
133         }
134         if (mode & S_IWGRP) {
135                 aces[2].access_mask |= 
136                         SEC_FILE_WRITE_DATA | 
137                         SEC_FILE_APPEND_DATA |
138                         SEC_FILE_WRITE_EA |
139                         SEC_FILE_WRITE_ATTRIBUTE;
140         }
141
142         if (mode & S_IROTH) {
143                 aces[3].access_mask |= 
144                         SEC_FILE_READ_DATA | 
145                         SEC_FILE_READ_EA |
146                         SEC_FILE_READ_ATTRIBUTE |
147                         SEC_FILE_EXECUTE |
148                         SEC_STD_SYNCHRONIZE |
149                         SEC_STD_READ_CONTROL;
150         }
151         if (mode & S_IWOTH) {
152                 aces[3].access_mask |= 
153                         SEC_FILE_WRITE_DATA | 
154                         SEC_FILE_APPEND_DATA |
155                         SEC_FILE_WRITE_EA |
156                         SEC_FILE_WRITE_ATTRIBUTE;
157         }
158
159         sid = dom_sid_parse_talloc(sd, SID_BUILTIN_ADMINISTRATORS);
160         if (sid == NULL) return NT_STATUS_NO_MEMORY;
161
162         aces[0].type = SEC_ACE_TYPE_ACCESS_ALLOWED;
163         aces[0].flags = 0;
164         aces[0].trustee = *sid;
165
166         aces[1].type = SEC_ACE_TYPE_ACCESS_ALLOWED;
167         aces[1].flags = 0;
168         aces[1].trustee = *sd->owner_sid;
169
170         aces[2].type = SEC_ACE_TYPE_ACCESS_ALLOWED;
171         aces[2].flags = 0;
172         aces[2].trustee = *sd->group_sid;
173
174         sid = dom_sid_parse_talloc(sd, SID_WORLD);
175         if (sid == NULL) return NT_STATUS_NO_MEMORY;
176
177         aces[3].type = SEC_ACE_TYPE_ACCESS_ALLOWED;
178         aces[3].flags = 0;
179         aces[3].trustee = *sid;
180
181         for (i=0;i<4;i++) {
182                 security_descriptor_dacl_add(sd, &aces[i]);
183         }
184         
185         acl->version = 1;
186         acl->info.sd = sd;
187
188         return NT_STATUS_OK;
189 }
190                                  
191
192 /*
193   omit any security_descriptor elements not specified in the given
194   secinfo flags
195 */
196 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
197 {
198         if (!(secinfo_flags & SECINFO_OWNER)) {
199                 sd->owner_sid = NULL;
200         }
201         if (!(secinfo_flags & SECINFO_GROUP)) {
202                 sd->group_sid = NULL;
203         }
204         if (!(secinfo_flags & SECINFO_DACL)) {
205                 sd->dacl = NULL;
206         }
207         if (!(secinfo_flags & SECINFO_SACL)) {
208                 sd->sacl = NULL;
209         }
210 }
211
212 /*
213   answer a setfileinfo for an ACL
214 */
215 NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, 
216                       struct smbsrv_request *req,
217                       struct pvfs_filename *name, int fd, 
218                       union smb_setfileinfo *info)
219 {
220         struct xattr_NTACL *acl;
221         uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
222         struct security_descriptor *new_sd, *sd;
223         NTSTATUS status;
224
225         acl = talloc_p(req, struct xattr_NTACL);
226         if (acl == NULL) {
227                 return NT_STATUS_NO_MEMORY;
228         }
229
230         status = pvfs_acl_load(pvfs, name, fd, acl);
231         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
232                 status = pvfs_default_acl(pvfs, req, name, fd, acl);
233         }
234         if (!NT_STATUS_IS_OK(status)) {
235                 return status;
236         }
237
238         switch (acl->version) {
239         case 1:
240                 sd = acl->info.sd;
241                 break;
242         default:
243                 return NT_STATUS_INVALID_ACL;
244         }
245
246         new_sd = info->set_secdesc.in.sd;
247
248         /* only set the elements that have been specified */
249         if (secinfo_flags & SECINFO_OWNER) {
250                 sd->owner_sid = new_sd->owner_sid;
251         }
252         if (secinfo_flags & SECINFO_GROUP) {
253                 sd->group_sid = new_sd->group_sid;
254         }
255         if (secinfo_flags & SECINFO_DACL) {
256                 sd->dacl = new_sd->dacl;
257                 pvfs_translate_generic_bits(sd->dacl);
258         }
259         if (secinfo_flags & SECINFO_SACL) {
260                 sd->sacl = new_sd->sacl;
261                 pvfs_translate_generic_bits(sd->sacl);
262         }
263
264         status = pvfs_acl_save(pvfs, name, fd, acl);
265
266         return status;
267 }
268
269
270 /*
271   answer a fileinfo query for the ACL
272 */
273 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs, 
274                         struct smbsrv_request *req,
275                         struct pvfs_filename *name, int fd, 
276                         union smb_fileinfo *info)
277 {
278         struct xattr_NTACL *acl;
279         NTSTATUS status;
280         struct security_descriptor *sd;
281
282         acl = talloc_p(req, struct xattr_NTACL);
283         if (acl == NULL) {
284                 return NT_STATUS_NO_MEMORY;
285         }
286
287         status = pvfs_acl_load(pvfs, name, fd, acl);
288         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
289                 status = pvfs_default_acl(pvfs, req, name, fd, acl);
290         }
291         if (!NT_STATUS_IS_OK(status)) {
292                 return status;
293         }
294
295         switch (acl->version) {
296         case 1:
297                 sd = acl->info.sd;
298                 break;
299         default:
300                 return NT_STATUS_INVALID_ACL;
301         }
302
303         normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
304
305         info->query_secdesc.out.sd = sd;
306
307         return NT_STATUS_OK;
308 }
309
310
311 /*
312   default access check function based on unix permissions
313   doing this saves on building a full security descriptor
314   for the common case of access check on files with no 
315   specific NT ACL
316 */
317 NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs, 
318                                 struct smbsrv_request *req,
319                                 struct pvfs_filename *name,
320                                 uint32_t *access_mask)
321 {
322         uid_t uid = geteuid();
323         uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
324
325         /* owner and root get extra permissions */
326         if (uid == 0 || uid == name->st.st_uid) {
327                 max_bits |= SEC_STD_ALL;
328         }
329
330         if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
331                 *access_mask = max_bits;
332                 return NT_STATUS_OK;
333         }
334
335         if (*access_mask & ~max_bits) {
336                 return NT_STATUS_ACCESS_DENIED;
337         }
338
339         return NT_STATUS_OK;
340 }
341
342
343 /*
344   check the security descriptor on a file, if any
345   
346   *access_mask is modified with the access actually granted
347 */
348 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs, 
349                            struct smbsrv_request *req,
350                            struct pvfs_filename *name,
351                            uint32_t *access_mask)
352 {
353         struct security_token *token = req->session->session_info->security_token;
354         struct xattr_NTACL *acl;
355         NTSTATUS status;
356         struct security_descriptor *sd;
357
358         acl = talloc_p(req, struct xattr_NTACL);
359         if (acl == NULL) {
360                 return NT_STATUS_NO_MEMORY;
361         }
362
363         status = pvfs_acl_load(pvfs, name, -1, acl);
364         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
365                 talloc_free(acl);
366                 return pvfs_access_check_unix(pvfs, req, name, access_mask);
367         }
368         if (!NT_STATUS_IS_OK(status)) {
369                 return status;
370         }
371
372         switch (acl->version) {
373         case 1:
374                 sd = acl->info.sd;
375                 break;
376         default:
377                 return NT_STATUS_INVALID_ACL;
378         }
379
380         /* expand the generic access bits to file specific bits */
381         *access_mask = pvfs_translate_mask(*access_mask);
382
383         /* check the acl against the required access mask */
384         status = sec_access_check(sd, token, *access_mask, access_mask);
385
386         /* this bit is always granted, even if not asked for */
387         *access_mask |= SEC_FILE_READ_ATTRIBUTE;
388
389         talloc_free(acl);
390         
391         return status;
392 }
393
394
395 /*
396   a simplified interface to access check, designed for calls that
397   do not take or return an access check mask
398 */
399 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs, 
400                                   struct smbsrv_request *req,
401                                   struct pvfs_filename *name,
402                                   uint32_t access_needed)
403 {
404         return pvfs_access_check(pvfs, req, name, &access_needed);
405 }