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/xattr.h"
27 #include "libcli/security/security.h"
30 /* the list of currently registered ACL backends */
31 static struct pvfs_acl_backend {
32 const struct pvfs_acl_ops *ops;
34 static int num_backends;
37 register a pvfs acl backend.
39 The 'name' can be later used by other backends to find the operations
40 structure for this backend.
42 _PUBLIC_ NTSTATUS pvfs_acl_register(const struct pvfs_acl_ops *ops)
44 struct pvfs_acl_ops *new_ops;
46 if (pvfs_acl_backend_byname(ops->name) != NULL) {
47 DEBUG(0,("pvfs acl backend '%s' already registered\n", ops->name));
48 return NT_STATUS_OBJECT_NAME_COLLISION;
51 backends = talloc_realloc(talloc_autofree_context(), backends, struct pvfs_acl_backend, num_backends+1);
52 NT_STATUS_HAVE_NO_MEMORY(backends);
54 new_ops = talloc_memdup(backends, ops, sizeof(*ops));
55 new_ops->name = talloc_strdup(new_ops, ops->name);
57 backends[num_backends].ops = new_ops;
61 DEBUG(3,("NTVFS backend '%s' registered\n", ops->name));
68 return the operations structure for a named backend
70 _PUBLIC_ const struct pvfs_acl_ops *pvfs_acl_backend_byname(const char *name)
74 for (i=0;i<num_backends;i++) {
75 if (strcmp(backends[i].ops->name, name) == 0) {
76 return backends[i].ops;
85 map a single access_mask from generic to specific bits for files/dirs
87 static uint32_t pvfs_translate_mask(uint32_t access_mask)
89 if (access_mask & SEC_MASK_GENERIC) {
90 if (access_mask & SEC_GENERIC_READ) access_mask |= SEC_RIGHTS_FILE_READ;
91 if (access_mask & SEC_GENERIC_WRITE) access_mask |= SEC_RIGHTS_FILE_WRITE;
92 if (access_mask & SEC_GENERIC_EXECUTE) access_mask |= SEC_RIGHTS_FILE_EXECUTE;
93 if (access_mask & SEC_GENERIC_ALL) access_mask |= SEC_RIGHTS_FILE_ALL;
94 access_mask &= ~SEC_MASK_GENERIC;
101 map any generic access bits in the given acl
102 this relies on the fact that the mappings for files and directories
105 static void pvfs_translate_generic_bits(struct security_acl *acl)
111 for (i=0;i<acl->num_aces;i++) {
112 struct security_ace *ace = &acl->aces[i];
113 ace->access_mask = pvfs_translate_mask(ace->access_mask);
119 setup a default ACL for a file
121 static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs,
122 struct ntvfs_request *req,
123 struct pvfs_filename *name, int fd,
124 struct security_descriptor **psd)
126 struct security_descriptor *sd;
128 struct security_ace ace;
131 *psd = security_descriptor_initialise(req);
133 return NT_STATUS_NO_MEMORY;
137 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
138 if (!NT_STATUS_IS_OK(status)) {
141 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
142 if (!NT_STATUS_IS_OK(status)) {
146 sd->type |= SEC_DESC_DACL_PRESENT;
148 mode = name->st.st_mode;
151 we provide up to 4 ACEs
159 /* setup owner ACE */
160 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
162 ace.trustee = *sd->owner_sid;
165 if (mode & S_IRUSR) {
166 if (mode & S_IWUSR) {
167 ace.access_mask |= SEC_RIGHTS_FILE_ALL;
169 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
172 if (mode & S_IWUSR) {
173 ace.access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
175 if (ace.access_mask) {
176 security_descriptor_dacl_add(sd, &ace);
180 /* setup group ACE */
181 ace.trustee = *sd->group_sid;
183 if (mode & S_IRGRP) {
184 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
186 if (mode & S_IWGRP) {
187 /* note that delete is not granted - this matches posix behaviour */
188 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
190 if (ace.access_mask) {
191 security_descriptor_dacl_add(sd, &ace);
194 /* setup other ACE */
195 ace.trustee = *dom_sid_parse_talloc(req, SID_WORLD);
197 if (mode & S_IROTH) {
198 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
200 if (mode & S_IWOTH) {
201 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
203 if (ace.access_mask) {
204 security_descriptor_dacl_add(sd, &ace);
207 /* setup system ACE */
208 ace.trustee = *dom_sid_parse_talloc(req, SID_NT_SYSTEM);
209 ace.access_mask = SEC_RIGHTS_FILE_ALL;
210 security_descriptor_dacl_add(sd, &ace);
217 omit any security_descriptor elements not specified in the given
220 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
222 if (!(secinfo_flags & SECINFO_OWNER)) {
223 sd->owner_sid = NULL;
225 if (!(secinfo_flags & SECINFO_GROUP)) {
226 sd->group_sid = NULL;
228 if (!(secinfo_flags & SECINFO_DACL)) {
231 if (!(secinfo_flags & SECINFO_SACL)) {
237 answer a setfileinfo for an ACL
239 NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
240 struct ntvfs_request *req,
241 struct pvfs_filename *name, int fd,
242 uint32_t access_mask,
243 union smb_setfileinfo *info)
245 uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
246 struct security_descriptor *new_sd, *sd, orig_sd;
247 NTSTATUS status = NT_STATUS_NOT_FOUND;
253 if (pvfs->acl_ops != NULL) {
254 status = pvfs->acl_ops->acl_load(pvfs, name, fd, req, &sd);
256 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
257 status = pvfs_default_acl(pvfs, req, name, fd, &sd);
259 if (!NT_STATUS_IS_OK(status)) {
263 new_sd = info->set_secdesc.in.sd;
266 old_uid = name->st.st_uid;
267 old_gid = name->st.st_gid;
269 /* only set the elements that have been specified */
270 if (secinfo_flags & SECINFO_OWNER) {
271 if (!(access_mask & SEC_STD_WRITE_OWNER)) {
272 return NT_STATUS_ACCESS_DENIED;
274 if (!dom_sid_equal(sd->owner_sid, new_sd->owner_sid)) {
275 status = sidmap_sid_to_unixuid(pvfs->sidmap, new_sd->owner_sid, &new_uid);
276 NT_STATUS_NOT_OK_RETURN(status);
278 sd->owner_sid = new_sd->owner_sid;
280 if (secinfo_flags & SECINFO_GROUP) {
281 if (!(access_mask & SEC_STD_WRITE_OWNER)) {
282 return NT_STATUS_ACCESS_DENIED;
284 if (!dom_sid_equal(sd->group_sid, new_sd->group_sid)) {
285 status = sidmap_sid_to_unixgid(pvfs->sidmap, new_sd->group_sid, &new_gid);
286 NT_STATUS_NOT_OK_RETURN(status);
288 sd->group_sid = new_sd->group_sid;
290 if (secinfo_flags & SECINFO_DACL) {
291 if (!(access_mask & SEC_STD_WRITE_DAC)) {
292 return NT_STATUS_ACCESS_DENIED;
294 sd->dacl = new_sd->dacl;
295 pvfs_translate_generic_bits(sd->dacl);
297 if (secinfo_flags & SECINFO_SACL) {
298 if (!(access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
299 return NT_STATUS_ACCESS_DENIED;
301 sd->sacl = new_sd->sacl;
302 pvfs_translate_generic_bits(sd->sacl);
305 if (new_uid == old_uid) {
309 if (new_gid == old_gid) {
313 /* if there's something to change try it */
314 if (new_uid != -1 || new_gid != -1) {
317 ret = chown(name->full_name, new_uid, new_gid);
319 ret = fchown(fd, new_uid, new_gid);
322 return pvfs_map_errno(pvfs, errno);
326 /* we avoid saving if the sd is the same. This means when clients
327 copy files and end up copying the default sd that we don't
328 needlessly use xattrs */
329 if (!security_descriptor_equal(sd, &orig_sd) && pvfs->acl_ops) {
330 status = pvfs->acl_ops->acl_save(pvfs, name, fd, sd);
338 answer a fileinfo query for the ACL
340 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs,
341 struct ntvfs_request *req,
342 struct pvfs_filename *name, int fd,
343 union smb_fileinfo *info)
345 NTSTATUS status = NT_STATUS_NOT_FOUND;
346 struct security_descriptor *sd;
349 status = pvfs->acl_ops->acl_load(pvfs, name, fd, req, &sd);
351 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
352 status = pvfs_default_acl(pvfs, req, name, fd, &sd);
354 if (!NT_STATUS_IS_OK(status)) {
358 normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
360 info->query_secdesc.out.sd = sd;
367 check the read only bit against any of the write access bits
369 static BOOL pvfs_read_only(struct pvfs_state *pvfs, uint32_t access_mask)
371 if ((pvfs->flags & PVFS_FLAG_READONLY) &&
372 (access_mask & (SEC_FILE_WRITE_DATA |
373 SEC_FILE_APPEND_DATA |
375 SEC_FILE_WRITE_ATTRIBUTE |
378 SEC_STD_WRITE_OWNER |
379 SEC_DIR_DELETE_CHILD))) {
386 default access check function based on unix permissions
387 doing this saves on building a full security descriptor
388 for the common case of access check on files with no
391 NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
392 struct ntvfs_request *req,
393 struct pvfs_filename *name,
394 uint32_t *access_mask)
396 uid_t uid = geteuid();
397 uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
399 if (pvfs_read_only(pvfs, *access_mask)) {
400 return NT_STATUS_ACCESS_DENIED;
403 /* owner and root get extra permissions */
405 max_bits |= SEC_STD_ALL | SEC_FLAG_SYSTEM_SECURITY;
406 } else if (uid == name->st.st_uid) {
407 max_bits |= SEC_STD_ALL;
410 if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
411 *access_mask = max_bits;
415 if (uid != 0 && (*access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
416 return NT_STATUS_PRIVILEGE_NOT_HELD;
419 if (*access_mask & ~max_bits) {
420 return NT_STATUS_ACCESS_DENIED;
423 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
430 check the security descriptor on a file, if any
432 *access_mask is modified with the access actually granted
434 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
435 struct ntvfs_request *req,
436 struct pvfs_filename *name,
437 uint32_t *access_mask)
439 struct security_token *token = req->session_info->security_token;
440 struct xattr_NTACL *acl;
442 struct security_descriptor *sd;
444 if (pvfs_read_only(pvfs, *access_mask)) {
445 return NT_STATUS_ACCESS_DENIED;
448 acl = talloc(req, struct xattr_NTACL);
450 return NT_STATUS_NO_MEMORY;
453 /* expand the generic access bits to file specific bits */
454 *access_mask = pvfs_translate_mask(*access_mask);
455 *access_mask &= ~SEC_FILE_READ_ATTRIBUTE;
457 status = pvfs_acl_load(pvfs, name, -1, acl);
458 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
460 return pvfs_access_check_unix(pvfs, req, name, access_mask);
462 if (!NT_STATUS_IS_OK(status)) {
466 switch (acl->version) {
471 return NT_STATUS_INVALID_ACL;
474 /* check the acl against the required access mask */
475 status = sec_access_check(sd, token, *access_mask, access_mask);
477 /* this bit is always granted, even if not asked for */
478 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
487 a simplified interface to access check, designed for calls that
488 do not take or return an access check mask
490 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs,
491 struct ntvfs_request *req,
492 struct pvfs_filename *name,
493 uint32_t access_needed)
495 if (access_needed == 0) {
498 return pvfs_access_check(pvfs, req, name, &access_needed);
502 access check for creating a new file/directory
504 NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs,
505 struct ntvfs_request *req,
506 struct pvfs_filename *name,
507 uint32_t *access_mask)
509 struct pvfs_filename *parent;
512 status = pvfs_resolve_parent(pvfs, req, name, &parent);
513 if (!NT_STATUS_IS_OK(status)) {
517 status = pvfs_access_check(pvfs, req, parent, access_mask);
518 if (!NT_STATUS_IS_OK(status)) {
522 if (! ((*access_mask) & SEC_DIR_ADD_FILE)) {
523 return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
530 access check for creating a new file/directory - no access mask supplied
532 NTSTATUS pvfs_access_check_parent(struct pvfs_state *pvfs,
533 struct ntvfs_request *req,
534 struct pvfs_filename *name,
535 uint32_t access_mask)
537 struct pvfs_filename *parent;
540 status = pvfs_resolve_parent(pvfs, req, name, &parent);
541 if (!NT_STATUS_IS_OK(status)) {
545 return pvfs_access_check_simple(pvfs, req, parent, access_mask);
550 determine if an ACE is inheritable
552 static BOOL pvfs_inheritable_ace(struct pvfs_state *pvfs,
553 const struct security_ace *ace,
557 return (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0;
560 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
564 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
565 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
573 this is the core of ACL inheritance. It copies any inheritable
574 aces from the parent SD to the child SD. Note that the algorithm
575 depends on whether the child is a container or not
577 static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs,
578 struct security_descriptor *parent_sd,
579 struct security_descriptor *sd,
584 for (i=0;i<parent_sd->dacl->num_aces;i++) {
585 struct security_ace ace = parent_sd->dacl->aces[i];
587 const struct dom_sid *creator = NULL, *new_id = NULL;
590 if (!pvfs_inheritable_ace(pvfs, &ace, container)) {
594 orig_flags = ace.flags;
596 /* see the RAW-ACLS inheritance test for details on these rules */
600 ace.flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
602 if (!(ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
603 ace.flags |= SEC_ACE_FLAG_INHERIT_ONLY;
605 if (ace.flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
610 /* the CREATOR sids are special when inherited */
611 if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_owner)) {
612 creator = pvfs->sid_cache.creator_owner;
613 new_id = sd->owner_sid;
614 } else if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_group)) {
615 creator = pvfs->sid_cache.creator_group;
616 new_id = sd->group_sid;
618 new_id = &ace.trustee;
621 if (creator && container &&
622 (ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
623 uint32_t flags = ace.flags;
625 ace.trustee = *new_id;
627 status = security_descriptor_dacl_add(sd, &ace);
628 if (!NT_STATUS_IS_OK(status)) {
632 ace.trustee = *creator;
633 ace.flags = flags | SEC_ACE_FLAG_INHERIT_ONLY;
634 status = security_descriptor_dacl_add(sd, &ace);
635 } else if (container &&
636 !(orig_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
637 status = security_descriptor_dacl_add(sd, &ace);
639 ace.trustee = *new_id;
640 status = security_descriptor_dacl_add(sd, &ace);
643 if (!NT_STATUS_IS_OK(status)) {
654 setup an ACL on a new file/directory based on the inherited ACL from
655 the parent. If there is no inherited ACL then we don't set anything,
656 as the default ACL applies anyway
658 NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
659 struct ntvfs_request *req,
660 struct pvfs_filename *name,
663 struct xattr_NTACL *acl;
665 struct pvfs_filename *parent;
666 struct security_descriptor *parent_sd, *sd;
669 /* form the parents path */
670 status = pvfs_resolve_parent(pvfs, req, name, &parent);
671 if (!NT_STATUS_IS_OK(status)) {
675 acl = talloc(req, struct xattr_NTACL);
677 return NT_STATUS_NO_MEMORY;
680 status = pvfs_acl_load(pvfs, parent, -1, acl);
681 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
684 if (!NT_STATUS_IS_OK(status)) {
688 switch (acl->version) {
690 parent_sd = acl->info.sd;
693 return NT_STATUS_INVALID_ACL;
696 if (parent_sd == NULL ||
697 parent_sd->dacl == NULL ||
698 parent_sd->dacl->num_aces == 0) {
699 /* go with the default ACL */
703 /* create the new sd */
704 sd = security_descriptor_initialise(req);
706 return NT_STATUS_NO_MEMORY;
709 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
710 if (!NT_STATUS_IS_OK(status)) {
713 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
714 if (!NT_STATUS_IS_OK(status)) {
718 sd->type |= SEC_DESC_DACL_PRESENT;
720 container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? True:False;
722 /* fill in the aces from the parent */
723 status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container);
724 if (!NT_STATUS_IS_OK(status)) {
728 /* if there is nothing to inherit then we fallback to the
730 if (sd->dacl == NULL || sd->dacl->num_aces == 0) {
736 status = pvfs_acl_save(pvfs, name, fd, acl);