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;
74 const char *sid_names[] = {
75 SID_BUILTIN_ADMINISTRATORS,
80 uint32_t access_masks[4];
83 sd = security_descriptor_initialise(req);
85 return NT_STATUS_NO_MEMORY;
88 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
89 if (!NT_STATUS_IS_OK(status)) {
92 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
93 if (!NT_STATUS_IS_OK(status)) {
97 sd->type |= SEC_DESC_DACL_PRESENT;
106 access_masks[0] = SEC_RIGHTS_FILE_ALL;
111 mode = name->st.st_mode;
113 if (mode & S_IRUSR) {
117 SEC_FILE_READ_ATTRIBUTE |
119 SEC_STD_SYNCHRONIZE |
120 SEC_STD_READ_CONTROL;
122 if (mode & S_IWUSR) {
124 SEC_FILE_WRITE_DATA |
125 SEC_FILE_APPEND_DATA |
127 SEC_FILE_WRITE_ATTRIBUTE |
131 if (mode & S_IRGRP) {
135 SEC_FILE_READ_ATTRIBUTE |
137 SEC_STD_SYNCHRONIZE |
138 SEC_STD_READ_CONTROL;
140 if (mode & S_IWGRP) {
142 SEC_FILE_WRITE_DATA |
143 SEC_FILE_APPEND_DATA |
145 SEC_FILE_WRITE_ATTRIBUTE;
148 if (mode & S_IROTH) {
152 SEC_FILE_READ_ATTRIBUTE |
154 SEC_STD_SYNCHRONIZE |
155 SEC_STD_READ_CONTROL;
157 if (mode & S_IWOTH) {
159 SEC_FILE_WRITE_DATA |
160 SEC_FILE_APPEND_DATA |
162 SEC_FILE_WRITE_ATTRIBUTE;
165 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
168 for (i=0;i<ARRAY_SIZE(sid_names);i++) {
171 ace.access_mask = access_masks[i];
173 sid = dom_sid_parse_talloc(sd, sid_names[i]);
175 return NT_STATUS_NO_MEMORY;
179 status = security_descriptor_dacl_add(sd, &ace);
180 if (!NT_STATUS_IS_OK(status)) {
193 omit any security_descriptor elements not specified in the given
196 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
198 if (!(secinfo_flags & SECINFO_OWNER)) {
199 sd->owner_sid = NULL;
201 if (!(secinfo_flags & SECINFO_GROUP)) {
202 sd->group_sid = NULL;
204 if (!(secinfo_flags & SECINFO_DACL)) {
207 if (!(secinfo_flags & SECINFO_SACL)) {
213 answer a setfileinfo for an ACL
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)
220 struct xattr_NTACL *acl;
221 uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
222 struct security_descriptor *new_sd, *sd;
225 acl = talloc_p(req, struct xattr_NTACL);
227 return NT_STATUS_NO_MEMORY;
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);
234 if (!NT_STATUS_IS_OK(status)) {
238 switch (acl->version) {
243 return NT_STATUS_INVALID_ACL;
246 new_sd = info->set_secdesc.in.sd;
248 /* only set the elements that have been specified */
249 if (secinfo_flags & SECINFO_OWNER) {
250 sd->owner_sid = new_sd->owner_sid;
252 if (secinfo_flags & SECINFO_GROUP) {
253 sd->group_sid = new_sd->group_sid;
255 if (secinfo_flags & SECINFO_DACL) {
256 sd->dacl = new_sd->dacl;
257 pvfs_translate_generic_bits(sd->dacl);
259 if (secinfo_flags & SECINFO_SACL) {
260 sd->sacl = new_sd->sacl;
261 pvfs_translate_generic_bits(sd->sacl);
264 status = pvfs_acl_save(pvfs, name, fd, acl);
271 answer a fileinfo query for the ACL
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)
278 struct xattr_NTACL *acl;
280 struct security_descriptor *sd;
282 acl = talloc_p(req, struct xattr_NTACL);
284 return NT_STATUS_NO_MEMORY;
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);
291 if (!NT_STATUS_IS_OK(status)) {
295 switch (acl->version) {
300 return NT_STATUS_INVALID_ACL;
303 normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
305 info->query_secdesc.out.sd = sd;
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
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)
322 uid_t uid = geteuid();
323 uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
325 /* owner and root get extra permissions */
326 if (uid == 0 || uid == name->st.st_uid) {
327 max_bits |= SEC_STD_ALL;
330 if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
331 *access_mask = max_bits;
335 if (*access_mask & ~max_bits) {
336 return NT_STATUS_ACCESS_DENIED;
344 check the security descriptor on a file, if any
346 *access_mask is modified with the access actually granted
348 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
349 struct smbsrv_request *req,
350 struct pvfs_filename *name,
351 uint32_t *access_mask)
353 struct nt_user_token *token = req->session->session_info->nt_user_token;
354 struct xattr_NTACL *acl;
356 struct security_descriptor *sd;
358 acl = talloc_p(req, struct xattr_NTACL);
360 return NT_STATUS_NO_MEMORY;
363 status = pvfs_acl_load(pvfs, name, -1, acl);
364 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
366 return pvfs_access_check_unix(pvfs, req, name, access_mask);
368 if (!NT_STATUS_IS_OK(status)) {
372 switch (acl->version) {
377 return NT_STATUS_INVALID_ACL;
380 /* expand the generic access bits to file specific bits */
381 *access_mask = pvfs_translate_mask(*access_mask);
383 /* check the acl against the required access mask */
384 status = sec_access_check(sd, token, *access_mask, access_mask);
386 /* this bit is always granted, even if not asked for */
387 *access_mask |= SEC_FILE_READ_ATTRIBUTE;