2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - ACL support
6 Copyright (C) Andrew Tridgell 2004
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.
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.
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.
24 #include "auth/auth.h"
25 #include "system/filesys.h"
26 #include "vfs_posix.h"
27 #include "librpc/gen_ndr/ndr_xattr.h"
31 map a single access_mask from generic to specific bits for files/dirs
33 static uint32_t pvfs_translate_mask(uint32_t access_mask)
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;
47 map any generic access bits in the given acl
48 this relies on the fact that the mappings for files and directories
51 static void pvfs_translate_generic_bits(struct security_acl *acl)
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);
63 setup a default ACL for a file
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)
70 struct security_descriptor *sd;
72 struct security_ace ace;
75 sd = security_descriptor_initialise(req);
77 return NT_STATUS_NO_MEMORY;
80 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
81 if (!NT_STATUS_IS_OK(status)) {
84 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
85 if (!NT_STATUS_IS_OK(status)) {
89 sd->type |= SEC_DESC_DACL_PRESENT;
91 mode = name->st.st_mode;
94 we provide up to 4 ACEs
102 /* setup owner ACE */
103 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
105 ace.trustee = *sd->owner_sid;
108 if (mode & S_IRUSR) {
109 if (mode & S_IWUSR) {
110 ace.access_mask |= SEC_RIGHTS_FILE_ALL;
112 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
115 if (mode & S_IWUSR) {
116 ace.access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
118 if (ace.access_mask) {
119 security_descriptor_dacl_add(sd, &ace);
123 /* setup group ACE */
124 ace.trustee = *sd->group_sid;
126 if (mode & S_IRGRP) {
127 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
129 if (mode & S_IWGRP) {
130 /* note that delete is not granted - this matches posix behaviour */
131 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
133 if (ace.access_mask) {
134 security_descriptor_dacl_add(sd, &ace);
137 /* setup other ACE */
138 ace.trustee = *dom_sid_parse_talloc(req, SID_WORLD);
140 if (mode & S_IROTH) {
141 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
143 if (mode & S_IWOTH) {
144 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
146 if (ace.access_mask) {
147 security_descriptor_dacl_add(sd, &ace);
150 /* setup system ACE */
151 ace.trustee = *dom_sid_parse_talloc(req, SID_NT_SYSTEM);
152 ace.access_mask = SEC_RIGHTS_FILE_ALL;
153 security_descriptor_dacl_add(sd, &ace);
163 omit any security_descriptor elements not specified in the given
166 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
168 if (!(secinfo_flags & SECINFO_OWNER)) {
169 sd->owner_sid = NULL;
171 if (!(secinfo_flags & SECINFO_GROUP)) {
172 sd->group_sid = NULL;
174 if (!(secinfo_flags & SECINFO_DACL)) {
177 if (!(secinfo_flags & SECINFO_SACL)) {
183 answer a setfileinfo for an ACL
185 NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
186 struct smbsrv_request *req,
187 struct pvfs_filename *name, int fd,
188 union smb_setfileinfo *info)
190 struct xattr_NTACL *acl;
191 uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
192 struct security_descriptor *new_sd, *sd;
195 acl = talloc_p(req, struct xattr_NTACL);
197 return NT_STATUS_NO_MEMORY;
200 status = pvfs_acl_load(pvfs, name, fd, acl);
201 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
202 status = pvfs_default_acl(pvfs, req, name, fd, acl);
204 if (!NT_STATUS_IS_OK(status)) {
208 switch (acl->version) {
213 return NT_STATUS_INVALID_ACL;
216 new_sd = info->set_secdesc.in.sd;
218 /* only set the elements that have been specified */
219 if (secinfo_flags & SECINFO_OWNER) {
220 sd->owner_sid = new_sd->owner_sid;
222 if (secinfo_flags & SECINFO_GROUP) {
223 sd->group_sid = new_sd->group_sid;
225 if (secinfo_flags & SECINFO_DACL) {
226 sd->dacl = new_sd->dacl;
227 pvfs_translate_generic_bits(sd->dacl);
229 if (secinfo_flags & SECINFO_SACL) {
230 sd->sacl = new_sd->sacl;
231 pvfs_translate_generic_bits(sd->sacl);
234 status = pvfs_acl_save(pvfs, name, fd, acl);
241 answer a fileinfo query for the ACL
243 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs,
244 struct smbsrv_request *req,
245 struct pvfs_filename *name, int fd,
246 union smb_fileinfo *info)
248 struct xattr_NTACL *acl;
250 struct security_descriptor *sd;
252 acl = talloc_p(req, struct xattr_NTACL);
254 return NT_STATUS_NO_MEMORY;
257 status = pvfs_acl_load(pvfs, name, fd, acl);
258 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
259 status = pvfs_default_acl(pvfs, req, name, fd, acl);
261 if (!NT_STATUS_IS_OK(status)) {
265 switch (acl->version) {
270 return NT_STATUS_INVALID_ACL;
273 normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
275 info->query_secdesc.out.sd = sd;
282 default access check function based on unix permissions
283 doing this saves on building a full security descriptor
284 for the common case of access check on files with no
287 NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
288 struct smbsrv_request *req,
289 struct pvfs_filename *name,
290 uint32_t *access_mask)
292 uid_t uid = geteuid();
293 uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
295 /* owner and root get extra permissions */
296 if (uid == 0 || uid == name->st.st_uid) {
297 max_bits |= SEC_STD_ALL;
300 if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
301 *access_mask = max_bits;
305 if (*access_mask & ~max_bits) {
306 return NT_STATUS_ACCESS_DENIED;
309 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
316 check the security descriptor on a file, if any
318 *access_mask is modified with the access actually granted
320 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
321 struct smbsrv_request *req,
322 struct pvfs_filename *name,
323 uint32_t *access_mask)
325 struct security_token *token = req->session->session_info->security_token;
326 struct xattr_NTACL *acl;
328 struct security_descriptor *sd;
330 acl = talloc_p(req, struct xattr_NTACL);
332 return NT_STATUS_NO_MEMORY;
335 status = pvfs_acl_load(pvfs, name, -1, acl);
336 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
338 return pvfs_access_check_unix(pvfs, req, name, access_mask);
340 if (!NT_STATUS_IS_OK(status)) {
344 switch (acl->version) {
349 return NT_STATUS_INVALID_ACL;
352 /* expand the generic access bits to file specific bits */
353 *access_mask = pvfs_translate_mask(*access_mask);
355 /* check the acl against the required access mask */
356 status = sec_access_check(sd, token, *access_mask, access_mask);
358 /* this bit is always granted, even if not asked for */
359 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
368 a simplified interface to access check, designed for calls that
369 do not take or return an access check mask
371 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs,
372 struct smbsrv_request *req,
373 struct pvfs_filename *name,
374 uint32_t access_needed)
376 if (access_needed == 0) {
379 return pvfs_access_check(pvfs, req, name, &access_needed);
383 access check for creating a new file/directory
385 NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs,
386 struct smbsrv_request *req,
387 struct pvfs_filename *name)
389 struct pvfs_filename *parent;
392 status = pvfs_resolve_parent(pvfs, req, name, &parent);
393 if (!NT_STATUS_IS_OK(status)) {
397 return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
402 determine if an ACE is inheritable
404 static BOOL pvfs_inheritable_ace(struct pvfs_state *pvfs,
405 const struct security_ace *ace,
409 return (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0;
412 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
416 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
417 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
425 this is the core of ACL inheritance. It copies any inheritable
426 aces from the parent SD to the child SD. Note that the algorithm
427 depends on whether the child is a container or not
429 static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs,
430 struct security_descriptor *parent_sd,
431 struct security_descriptor *sd,
436 for (i=0;i<parent_sd->dacl->num_aces;i++) {
437 struct security_ace ace = parent_sd->dacl->aces[i];
440 if (!pvfs_inheritable_ace(pvfs, &ace, container)) {
444 /* see the RAW-ACLS inheritance test for details on these rules */
448 ace.flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
450 if (!(ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
451 ace.flags |= SEC_ACE_FLAG_INHERIT_ONLY;
453 if (ace.flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
458 status = security_descriptor_dacl_add(sd, &ace);
459 if (!NT_STATUS_IS_OK(status)) {
470 setup an ACL on a new file/directory based on the inherited ACL from
471 the parent. If there is no inherited ACL then we don't set anything,
472 as the default ACL applies anyway
474 NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
475 struct smbsrv_request *req,
476 struct pvfs_filename *name,
479 struct xattr_NTACL *acl;
481 struct pvfs_filename *parent;
482 struct security_descriptor *parent_sd, *sd;
485 /* form the parents path */
486 status = pvfs_resolve_parent(pvfs, req, name, &parent);
487 if (!NT_STATUS_IS_OK(status)) {
491 acl = talloc_p(req, struct xattr_NTACL);
493 return NT_STATUS_NO_MEMORY;
496 status = pvfs_acl_load(pvfs, parent, -1, acl);
497 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
500 if (!NT_STATUS_IS_OK(status)) {
504 switch (acl->version) {
506 parent_sd = acl->info.sd;
509 return NT_STATUS_INVALID_ACL;
512 if (parent_sd == NULL ||
513 parent_sd->dacl == NULL ||
514 parent_sd->dacl->num_aces == 0) {
515 /* go with the default ACL */
519 /* create the new sd */
520 sd = security_descriptor_initialise(req);
522 return NT_STATUS_NO_MEMORY;
525 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
526 if (!NT_STATUS_IS_OK(status)) {
529 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
530 if (!NT_STATUS_IS_OK(status)) {
534 sd->type |= SEC_DESC_DACL_PRESENT;
536 container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? True:False;
538 /* fill in the aces from the parent */
539 status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container);
540 if (!NT_STATUS_IS_OK(status)) {
544 /* if there is nothing to inherit then we fallback to the
546 if (sd->dacl == NULL || sd->dacl->num_aces == 0) {
552 status = pvfs_acl_save(pvfs, name, fd, acl);