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 "vfs_posix.h"
26 #include "librpc/gen_ndr/ndr_xattr.h"
27 #include "libcli/security/proto.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 ntvfs_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 ntvfs_request *req,
187 struct pvfs_filename *name, int fd,
188 uint32_t access_mask,
189 union smb_setfileinfo *info)
191 struct xattr_NTACL *acl;
192 uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
193 struct security_descriptor *new_sd, *sd, orig_sd;
198 acl = talloc(req, struct xattr_NTACL);
200 return NT_STATUS_NO_MEMORY;
203 status = pvfs_acl_load(pvfs, name, fd, acl);
204 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
205 status = pvfs_default_acl(pvfs, req, name, fd, acl);
207 if (!NT_STATUS_IS_OK(status)) {
211 switch (acl->version) {
216 return NT_STATUS_INVALID_ACL;
219 new_sd = info->set_secdesc.in.sd;
222 uid = name->st.st_uid;
223 gid = name->st.st_gid;
225 /* only set the elements that have been specified */
226 if ((secinfo_flags & SECINFO_OWNER) &&
227 !dom_sid_equal(sd->owner_sid, new_sd->owner_sid)) {
228 if (!(access_mask & SEC_STD_WRITE_OWNER)) {
229 return NT_STATUS_ACCESS_DENIED;
231 sd->owner_sid = new_sd->owner_sid;
232 status = sidmap_sid_to_unixuid(pvfs->sidmap, sd->owner_sid, &uid);
233 if (!NT_STATUS_IS_OK(status)) {
237 if ((secinfo_flags & SECINFO_GROUP) &&
238 !dom_sid_equal(sd->group_sid, new_sd->group_sid)) {
239 sd->group_sid = new_sd->group_sid;
240 status = sidmap_sid_to_unixgid(pvfs->sidmap, sd->owner_sid, &gid);
241 if (!NT_STATUS_IS_OK(status)) {
245 if (secinfo_flags & SECINFO_DACL) {
246 sd->dacl = new_sd->dacl;
247 pvfs_translate_generic_bits(sd->dacl);
249 if (secinfo_flags & SECINFO_SACL) {
250 sd->sacl = new_sd->sacl;
251 if (!(access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
252 return NT_STATUS_ACCESS_DENIED;
254 pvfs_translate_generic_bits(sd->sacl);
257 if (uid != -1 || gid != -1) {
260 ret = chown(name->full_name, uid, gid);
262 ret = fchown(fd, uid, gid);
265 return pvfs_map_errno(pvfs, errno);
269 /* we avoid saving if the sd is the same. This means when clients
270 copy files and end up copying the default sd that we don't
271 needlessly use xattrs */
272 if (!security_descriptor_equal(sd, &orig_sd)) {
273 status = pvfs_acl_save(pvfs, name, fd, acl);
281 answer a fileinfo query for the ACL
283 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs,
284 struct ntvfs_request *req,
285 struct pvfs_filename *name, int fd,
286 union smb_fileinfo *info)
288 struct xattr_NTACL *acl;
290 struct security_descriptor *sd;
292 acl = talloc(req, struct xattr_NTACL);
294 return NT_STATUS_NO_MEMORY;
297 status = pvfs_acl_load(pvfs, name, fd, acl);
298 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
299 status = pvfs_default_acl(pvfs, req, name, fd, acl);
301 if (!NT_STATUS_IS_OK(status)) {
305 switch (acl->version) {
310 return NT_STATUS_INVALID_ACL;
313 normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
315 info->query_secdesc.out.sd = sd;
322 default access check function based on unix permissions
323 doing this saves on building a full security descriptor
324 for the common case of access check on files with no
327 NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
328 struct ntvfs_request *req,
329 struct pvfs_filename *name,
330 uint32_t *access_mask)
332 uid_t uid = geteuid();
333 uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
335 /* owner and root get extra permissions */
336 if (uid == 0 || uid == name->st.st_uid) {
337 max_bits |= SEC_STD_ALL;
340 if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
341 *access_mask = max_bits;
345 if (*access_mask & ~max_bits) {
346 return NT_STATUS_ACCESS_DENIED;
349 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
356 check the security descriptor on a file, if any
358 *access_mask is modified with the access actually granted
360 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
361 struct ntvfs_request *req,
362 struct pvfs_filename *name,
363 uint32_t *access_mask)
365 struct security_token *token = req->session->session_info->security_token;
366 struct xattr_NTACL *acl;
368 struct security_descriptor *sd;
370 acl = talloc(req, struct xattr_NTACL);
372 return NT_STATUS_NO_MEMORY;
375 /* expand the generic access bits to file specific bits */
376 *access_mask = pvfs_translate_mask(*access_mask);
377 *access_mask &= ~SEC_FILE_READ_ATTRIBUTE;
379 status = pvfs_acl_load(pvfs, name, -1, acl);
380 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
382 return pvfs_access_check_unix(pvfs, req, name, access_mask);
384 if (!NT_STATUS_IS_OK(status)) {
388 switch (acl->version) {
393 return NT_STATUS_INVALID_ACL;
396 /* check the acl against the required access mask */
397 status = sec_access_check(sd, token, *access_mask, access_mask);
399 /* this bit is always granted, even if not asked for */
400 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
409 a simplified interface to access check, designed for calls that
410 do not take or return an access check mask
412 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs,
413 struct ntvfs_request *req,
414 struct pvfs_filename *name,
415 uint32_t access_needed)
417 if (access_needed == 0) {
420 return pvfs_access_check(pvfs, req, name, &access_needed);
424 access check for creating a new file/directory
426 NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs,
427 struct ntvfs_request *req,
428 struct pvfs_filename *name,
429 uint32_t *access_mask)
431 struct pvfs_filename *parent;
434 status = pvfs_resolve_parent(pvfs, req, name, &parent);
435 if (!NT_STATUS_IS_OK(status)) {
439 status = pvfs_access_check(pvfs, req, parent, access_mask);
440 if (!NT_STATUS_IS_OK(status)) {
444 if (! ((*access_mask) & SEC_DIR_ADD_FILE)) {
445 return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
452 access check for creating a new file/directory - no access mask supplied
454 NTSTATUS pvfs_access_check_parent(struct pvfs_state *pvfs,
455 struct ntvfs_request *req,
456 struct pvfs_filename *name,
457 uint32_t access_mask)
459 struct pvfs_filename *parent;
462 status = pvfs_resolve_parent(pvfs, req, name, &parent);
463 if (!NT_STATUS_IS_OK(status)) {
467 return pvfs_access_check_simple(pvfs, req, parent, access_mask);
472 determine if an ACE is inheritable
474 static BOOL pvfs_inheritable_ace(struct pvfs_state *pvfs,
475 const struct security_ace *ace,
479 return (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0;
482 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
486 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
487 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
495 this is the core of ACL inheritance. It copies any inheritable
496 aces from the parent SD to the child SD. Note that the algorithm
497 depends on whether the child is a container or not
499 static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs,
500 struct security_descriptor *parent_sd,
501 struct security_descriptor *sd,
506 for (i=0;i<parent_sd->dacl->num_aces;i++) {
507 struct security_ace ace = parent_sd->dacl->aces[i];
509 const struct dom_sid *creator = NULL, *new_id = NULL;
512 if (!pvfs_inheritable_ace(pvfs, &ace, container)) {
516 orig_flags = ace.flags;
518 /* see the RAW-ACLS inheritance test for details on these rules */
522 ace.flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
524 if (!(ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
525 ace.flags |= SEC_ACE_FLAG_INHERIT_ONLY;
527 if (ace.flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
532 /* the CREATOR sids are special when inherited */
533 if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_owner)) {
534 creator = pvfs->sid_cache.creator_owner;
535 new_id = sd->owner_sid;
536 } else if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_group)) {
537 creator = pvfs->sid_cache.creator_group;
538 new_id = sd->group_sid;
540 new_id = &ace.trustee;
543 if (creator && container &&
544 (ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
545 uint32_t flags = ace.flags;
547 ace.trustee = *new_id;
549 status = security_descriptor_dacl_add(sd, &ace);
550 if (!NT_STATUS_IS_OK(status)) {
554 ace.trustee = *creator;
555 ace.flags = flags | SEC_ACE_FLAG_INHERIT_ONLY;
556 status = security_descriptor_dacl_add(sd, &ace);
557 } else if (container &&
558 !(orig_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
559 status = security_descriptor_dacl_add(sd, &ace);
561 ace.trustee = *new_id;
562 status = security_descriptor_dacl_add(sd, &ace);
565 if (!NT_STATUS_IS_OK(status)) {
576 setup an ACL on a new file/directory based on the inherited ACL from
577 the parent. If there is no inherited ACL then we don't set anything,
578 as the default ACL applies anyway
580 NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
581 struct ntvfs_request *req,
582 struct pvfs_filename *name,
585 struct xattr_NTACL *acl;
587 struct pvfs_filename *parent;
588 struct security_descriptor *parent_sd, *sd;
591 /* form the parents path */
592 status = pvfs_resolve_parent(pvfs, req, name, &parent);
593 if (!NT_STATUS_IS_OK(status)) {
597 acl = talloc(req, struct xattr_NTACL);
599 return NT_STATUS_NO_MEMORY;
602 status = pvfs_acl_load(pvfs, parent, -1, acl);
603 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
606 if (!NT_STATUS_IS_OK(status)) {
610 switch (acl->version) {
612 parent_sd = acl->info.sd;
615 return NT_STATUS_INVALID_ACL;
618 if (parent_sd == NULL ||
619 parent_sd->dacl == NULL ||
620 parent_sd->dacl->num_aces == 0) {
621 /* go with the default ACL */
625 /* create the new sd */
626 sd = security_descriptor_initialise(req);
628 return NT_STATUS_NO_MEMORY;
631 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
632 if (!NT_STATUS_IS_OK(status)) {
635 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
636 if (!NT_STATUS_IS_OK(status)) {
640 sd->type |= SEC_DESC_DACL_PRESENT;
642 container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? True:False;
644 /* fill in the aces from the parent */
645 status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container);
646 if (!NT_STATUS_IS_OK(status)) {
650 /* if there is nothing to inherit then we fallback to the
652 if (sd->dacl == NULL || sd->dacl->num_aces == 0) {
658 status = pvfs_acl_save(pvfs, name, fd, acl);