r4391: bring the default ACL inline with what w2k3 uses
[samba.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 ace;
73         mode_t mode;
74
75         sd = security_descriptor_initialise(req);
76         if (sd == NULL) {
77                 return NT_STATUS_NO_MEMORY;
78         }
79
80         status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
81         if (!NT_STATUS_IS_OK(status)) {
82                 return status;
83         }
84         status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
85         if (!NT_STATUS_IS_OK(status)) {
86                 return status;
87         }
88
89         sd->type |= SEC_DESC_DACL_PRESENT;
90
91         mode = name->st.st_mode;
92
93         /*
94           we provide up to 4 ACEs
95             - Owner
96             - Group
97             - Everyone
98             - Administrator
99          */
100
101
102         /* setup owner ACE */
103         ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
104         ace.flags = 0;
105         ace.trustee = *sd->owner_sid;
106         ace.access_mask = 0;
107
108         if (mode & S_IRUSR) {
109                 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
110         }
111         if (mode & S_IWUSR) {
112                 ace.access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
113         }
114         if (ace.access_mask) {
115                 security_descriptor_dacl_add(sd, &ace);
116         }
117
118
119         /* setup group ACE */
120         ace.trustee = *sd->group_sid;
121         ace.access_mask = 0;
122         if (mode & S_IRGRP) {
123                 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
124         }
125         if (mode & S_IWGRP) {
126                 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
127         }
128         if (ace.access_mask) {
129                 security_descriptor_dacl_add(sd, &ace);
130         }
131
132         /* setup other ACE */
133         ace.trustee = *dom_sid_parse_talloc(req, SID_WORLD);
134         ace.access_mask = 0;
135         if (mode & S_IROTH) {
136                 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
137         }
138         if (mode & S_IWOTH) {
139                 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
140         }
141         if (ace.access_mask) {
142                 security_descriptor_dacl_add(sd, &ace);
143         }
144
145         /* setup system ACE */
146         ace.trustee = *dom_sid_parse_talloc(req, SID_NT_SYSTEM);
147         ace.access_mask = SEC_RIGHTS_FILE_ALL;
148         security_descriptor_dacl_add(sd, &ace);
149         
150         acl->version = 1;
151         acl->info.sd = sd;
152
153         return NT_STATUS_OK;
154 }
155                                  
156
157 /*
158   omit any security_descriptor elements not specified in the given
159   secinfo flags
160 */
161 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
162 {
163         if (!(secinfo_flags & SECINFO_OWNER)) {
164                 sd->owner_sid = NULL;
165         }
166         if (!(secinfo_flags & SECINFO_GROUP)) {
167                 sd->group_sid = NULL;
168         }
169         if (!(secinfo_flags & SECINFO_DACL)) {
170                 sd->dacl = NULL;
171         }
172         if (!(secinfo_flags & SECINFO_SACL)) {
173                 sd->sacl = NULL;
174         }
175 }
176
177 /*
178   answer a setfileinfo for an ACL
179 */
180 NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, 
181                       struct smbsrv_request *req,
182                       struct pvfs_filename *name, int fd, 
183                       union smb_setfileinfo *info)
184 {
185         struct xattr_NTACL *acl;
186         uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
187         struct security_descriptor *new_sd, *sd;
188         NTSTATUS status;
189
190         acl = talloc_p(req, struct xattr_NTACL);
191         if (acl == NULL) {
192                 return NT_STATUS_NO_MEMORY;
193         }
194
195         status = pvfs_acl_load(pvfs, name, fd, acl);
196         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
197                 status = pvfs_default_acl(pvfs, req, name, fd, acl);
198         }
199         if (!NT_STATUS_IS_OK(status)) {
200                 return status;
201         }
202
203         switch (acl->version) {
204         case 1:
205                 sd = acl->info.sd;
206                 break;
207         default:
208                 return NT_STATUS_INVALID_ACL;
209         }
210
211         new_sd = info->set_secdesc.in.sd;
212
213         /* only set the elements that have been specified */
214         if (secinfo_flags & SECINFO_OWNER) {
215                 sd->owner_sid = new_sd->owner_sid;
216         }
217         if (secinfo_flags & SECINFO_GROUP) {
218                 sd->group_sid = new_sd->group_sid;
219         }
220         if (secinfo_flags & SECINFO_DACL) {
221                 sd->dacl = new_sd->dacl;
222                 pvfs_translate_generic_bits(sd->dacl);
223         }
224         if (secinfo_flags & SECINFO_SACL) {
225                 sd->sacl = new_sd->sacl;
226                 pvfs_translate_generic_bits(sd->sacl);
227         }
228
229         status = pvfs_acl_save(pvfs, name, fd, acl);
230
231         return status;
232 }
233
234
235 /*
236   answer a fileinfo query for the ACL
237 */
238 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs, 
239                         struct smbsrv_request *req,
240                         struct pvfs_filename *name, int fd, 
241                         union smb_fileinfo *info)
242 {
243         struct xattr_NTACL *acl;
244         NTSTATUS status;
245         struct security_descriptor *sd;
246
247         acl = talloc_p(req, struct xattr_NTACL);
248         if (acl == NULL) {
249                 return NT_STATUS_NO_MEMORY;
250         }
251
252         status = pvfs_acl_load(pvfs, name, fd, acl);
253         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
254                 status = pvfs_default_acl(pvfs, req, name, fd, acl);
255         }
256         if (!NT_STATUS_IS_OK(status)) {
257                 return status;
258         }
259
260         switch (acl->version) {
261         case 1:
262                 sd = acl->info.sd;
263                 break;
264         default:
265                 return NT_STATUS_INVALID_ACL;
266         }
267
268         normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
269
270         info->query_secdesc.out.sd = sd;
271
272         return NT_STATUS_OK;
273 }
274
275
276 /*
277   default access check function based on unix permissions
278   doing this saves on building a full security descriptor
279   for the common case of access check on files with no 
280   specific NT ACL
281 */
282 NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs, 
283                                 struct smbsrv_request *req,
284                                 struct pvfs_filename *name,
285                                 uint32_t *access_mask)
286 {
287         uid_t uid = geteuid();
288         uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
289
290         /* owner and root get extra permissions */
291         if (uid == 0 || uid == name->st.st_uid) {
292                 max_bits |= SEC_STD_ALL;
293         }
294
295         if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
296                 *access_mask = max_bits;
297                 return NT_STATUS_OK;
298         }
299
300         if (*access_mask & ~max_bits) {
301                 return NT_STATUS_ACCESS_DENIED;
302         }
303
304         return NT_STATUS_OK;
305 }
306
307
308 /*
309   check the security descriptor on a file, if any
310   
311   *access_mask is modified with the access actually granted
312 */
313 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs, 
314                            struct smbsrv_request *req,
315                            struct pvfs_filename *name,
316                            uint32_t *access_mask)
317 {
318         struct security_token *token = req->session->session_info->security_token;
319         struct xattr_NTACL *acl;
320         NTSTATUS status;
321         struct security_descriptor *sd;
322
323         acl = talloc_p(req, struct xattr_NTACL);
324         if (acl == NULL) {
325                 return NT_STATUS_NO_MEMORY;
326         }
327
328         status = pvfs_acl_load(pvfs, name, -1, acl);
329         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
330                 talloc_free(acl);
331                 return pvfs_access_check_unix(pvfs, req, name, access_mask);
332         }
333         if (!NT_STATUS_IS_OK(status)) {
334                 return status;
335         }
336
337         switch (acl->version) {
338         case 1:
339                 sd = acl->info.sd;
340                 break;
341         default:
342                 return NT_STATUS_INVALID_ACL;
343         }
344
345         /* expand the generic access bits to file specific bits */
346         *access_mask = pvfs_translate_mask(*access_mask);
347
348         /* check the acl against the required access mask */
349         status = sec_access_check(sd, token, *access_mask, access_mask);
350
351         /* this bit is always granted, even if not asked for */
352         *access_mask |= SEC_FILE_READ_ATTRIBUTE;
353
354         talloc_free(acl);
355         
356         return status;
357 }
358
359
360 /*
361   a simplified interface to access check, designed for calls that
362   do not take or return an access check mask
363 */
364 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs, 
365                                   struct smbsrv_request *req,
366                                   struct pvfs_filename *name,
367                                   uint32_t access_needed)
368 {
369         return pvfs_access_check(pvfs, req, name, &access_needed);
370 }