2 * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ to NT acls and vice versa.
4 * Copyright (C) Jiri Sasek, 2007
5 * based on the foobar.c module which is copyrighted by Volker Lendecke
6 * based on pvfs_acl_nfs4.c Copyright (C) Andrew Tridgell 2006
8 * based on vfs_fake_acls:
9 * Copyright (C) Tim Potter, 1999-2000
10 * Copyright (C) Alexander Bokovoy, 2002
11 * Copyright (C) Andrew Bartlett, 2002,2012
12 * Copyright (C) Ralph Boehme 2017
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <http://www.gnu.org/licenses/>.
30 #include "system/filesys.h"
31 #include "smbd/smbd.h"
32 #include "libcli/security/security_token.h"
33 #include "nfs4_acls.h"
34 #include "librpc/gen_ndr/ndr_nfs4acl.h"
35 #include "nfs4acl_xattr.h"
36 #include "nfs4acl_xattr_ndr.h"
37 #include "nfs4acl_xattr_xdr.h"
40 #define DBGC_CLASS DBGC_VFS
42 static const struct enum_list nfs4acl_encoding
[] = {
43 {NFS4ACL_ENCODING_NDR
, "ndr"},
44 {NFS4ACL_ENCODING_XDR
, "xdr"},
48 * Check if someone changed the POSIX mode, for files we expect 0666, for
49 * directories 0777. Discard the ACL blob if the mode is different.
51 static bool nfs4acl_validate_blob(vfs_handle_struct
*handle
,
52 const struct smb_filename
*smb_fname
)
54 struct nfs4acl_config
*config
= NULL
;
59 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
60 struct nfs4acl_config
,
63 if (!VALID_STAT(smb_fname
->st
)) {
64 /* might be a create */
68 if (S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
73 if ((smb_fname
->st
.st_ex_mode
& expected_mode
) == expected_mode
) {
78 ret
= SMB_VFS_NEXT_REMOVEXATTR(handle
,
85 if (saved_errno
!= 0) {
88 if (ret
!= 0 && errno
!= ENOATTR
) {
89 DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno
));
96 static NTSTATUS
nfs4acl_get_blob(struct vfs_handle_struct
*handle
,
98 const struct smb_filename
*smb_fname_in
,
102 struct nfs4acl_config
*config
= NULL
;
103 const struct smb_filename
*smb_fname
= NULL
;
104 size_t allocsize
= 256;
108 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
109 struct nfs4acl_config
,
110 return NT_STATUS_INTERNAL_ERROR
);
112 *blob
= data_blob_null
;
114 if (fsp
== NULL
&& smb_fname_in
== NULL
) {
115 return NT_STATUS_INTERNAL_ERROR
;
117 smb_fname
= smb_fname_in
;
118 if (smb_fname
== NULL
) {
119 smb_fname
= fsp
->fsp_name
;
121 if (smb_fname
== NULL
) {
122 return NT_STATUS_INTERNAL_ERROR
;
125 ok
= nfs4acl_validate_blob(handle
, smb_fname
);
127 return NT_STATUS_INTERNAL_ERROR
;
134 ok
= data_blob_realloc(mem_ctx
, blob
, allocsize
);
136 return NT_STATUS_NO_MEMORY
;
140 if (fsp
!= NULL
&& fsp
->fh
->fd
!= -1) {
141 length
= SMB_VFS_NEXT_FGETXATTR(handle
,
147 length
= SMB_VFS_NEXT_GETXATTR(handle
,
157 if (saved_errno
!= 0) {
160 } while (length
== -1 && errno
== ERANGE
&& allocsize
<= 65536);
163 return map_nt_error_from_unix(errno
);
169 static NTSTATUS
nfs4acl_xattr_default_sd(
170 struct vfs_handle_struct
*handle
,
171 const struct smb_filename
*smb_fname
,
173 struct security_descriptor
**sd
)
175 struct nfs4acl_config
*config
= NULL
;
176 enum default_acl_style default_acl_style
;
177 mode_t required_mode
;
178 SMB_STRUCT_STAT sbuf
= smb_fname
->st
;
181 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
182 struct nfs4acl_config
,
183 return NT_STATUS_INTERNAL_ERROR
);
185 default_acl_style
= config
->default_acl_style
;
187 if (!VALID_STAT(sbuf
)) {
188 ret
= vfs_stat_smb_basename(handle
->conn
,
192 return map_nt_error_from_unix(errno
);
196 if (S_ISDIR(sbuf
.st_ex_mode
)) {
197 required_mode
= 0777;
199 required_mode
= 0666;
201 if ((sbuf
.st_ex_mode
& required_mode
) != required_mode
) {
202 default_acl_style
= DEFAULT_ACL_POSIX
;
205 return make_default_filesystem_acl(mem_ctx
,
207 smb_fname
->base_name
,
212 static NTSTATUS
nfs4acl_blob_to_smb4(struct vfs_handle_struct
*handle
,
215 struct SMB4ACL_T
**smb4acl
)
217 struct nfs4acl_config
*config
= NULL
;
220 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
221 struct nfs4acl_config
,
222 return NT_STATUS_INTERNAL_ERROR
);
224 switch (config
->encoding
) {
225 case NFS4ACL_ENCODING_NDR
:
226 status
= nfs4acl_ndr_blob_to_smb4(handle
, mem_ctx
, blob
, smb4acl
);
228 case NFS4ACL_ENCODING_XDR
:
229 status
= nfs4acl_xdr_blob_to_smb4(handle
, mem_ctx
, blob
, smb4acl
);
232 status
= NT_STATUS_INTERNAL_ERROR
;
239 static NTSTATUS
nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct
*handle
,
240 struct files_struct
*fsp
,
241 uint32_t security_info
,
243 struct security_descriptor
**sd
)
245 struct SMB4ACL_T
*smb4acl
= NULL
;
246 TALLOC_CTX
*frame
= talloc_stackframe();
250 status
= nfs4acl_get_blob(handle
, fsp
, NULL
, frame
, &blob
);
251 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
253 return nfs4acl_xattr_default_sd(
254 handle
, fsp
->fsp_name
, mem_ctx
, sd
);
256 if (!NT_STATUS_IS_OK(status
)) {
261 status
= nfs4acl_blob_to_smb4(handle
, &blob
, frame
, &smb4acl
);
262 if (!NT_STATUS_IS_OK(status
)) {
267 status
= smb_fget_nt_acl_nfs4(fsp
, NULL
, security_info
, mem_ctx
,
273 static NTSTATUS
nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct
*handle
,
274 const struct smb_filename
*smb_fname
,
275 uint32_t security_info
,
277 struct security_descriptor
**sd
)
279 struct SMB4ACL_T
*smb4acl
= NULL
;
280 TALLOC_CTX
*frame
= talloc_stackframe();
284 status
= nfs4acl_get_blob(handle
, NULL
, smb_fname
, frame
, &blob
);
285 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
287 return nfs4acl_xattr_default_sd(
288 handle
, smb_fname
, mem_ctx
, sd
);
290 if (!NT_STATUS_IS_OK(status
)) {
295 status
= nfs4acl_blob_to_smb4(handle
, &blob
, frame
, &smb4acl
);
296 if (!NT_STATUS_IS_OK(status
)) {
301 status
= smb_get_nt_acl_nfs4(handle
->conn
, smb_fname
, NULL
,
302 security_info
, mem_ctx
, sd
,
308 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct
*handle
,
310 struct SMB4ACL_T
*smb4acl
)
312 struct nfs4acl_config
*config
= NULL
;
318 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
319 struct nfs4acl_config
,
322 switch (config
->encoding
) {
323 case NFS4ACL_ENCODING_NDR
:
324 status
= nfs4acl_smb4acl_to_ndr_blob(handle
, talloc_tos(),
327 case NFS4ACL_ENCODING_XDR
:
328 status
= nfs4acl_smb4acl_to_xdr_blob(handle
, talloc_tos(),
332 status
= NT_STATUS_INTERNAL_ERROR
;
335 if (!NT_STATUS_IS_OK(status
)) {
340 if (fsp
->fh
->fd
!= -1) {
341 ret
= SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, config
->xattr_name
,
342 blob
.data
, blob
.length
, 0);
344 ret
= SMB_VFS_NEXT_SETXATTR(handle
, fsp
->fsp_name
,
346 blob
.data
, blob
.length
, 0);
352 data_blob_free(&blob
);
353 if (saved_errno
!= 0) {
357 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno
));
364 static NTSTATUS
nfs4acl_xattr_fset_nt_acl(vfs_handle_struct
*handle
,
366 uint32_t security_info_sent
,
367 const struct security_descriptor
*psd
)
369 struct nfs4acl_config
*config
= NULL
;
370 const struct security_token
*token
= NULL
;
371 mode_t existing_mode
;
372 mode_t expected_mode
;
373 mode_t restored_mode
;
374 bool chown_needed
= false;
378 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
379 struct nfs4acl_config
,
380 return NT_STATUS_INTERNAL_ERROR
);
382 if (!VALID_STAT(fsp
->fsp_name
->st
)) {
383 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp
));
384 return NT_STATUS_INTERNAL_ERROR
;
387 existing_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
388 if (S_ISDIR(existing_mode
)) {
389 expected_mode
= 0777;
391 expected_mode
= 0666;
393 if ((existing_mode
& expected_mode
) != expected_mode
) {
396 restored_mode
= existing_mode
| expected_mode
;
399 if (fsp
->fh
->fd
!= -1) {
400 ret
= SMB_VFS_NEXT_FCHMOD(handle
,
404 ret
= SMB_VFS_NEXT_CHMOD(handle
,
412 if (saved_errno
!= 0) {
416 DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
417 fsp_str_dbg(fsp
), existing_mode
,
419 return map_nt_error_from_unix(errno
);
423 status
= smb_set_nt_acl_nfs4(handle
,
425 &config
->nfs4_params
,
428 nfs4acl_smb4acl_set_fn
);
429 if (NT_STATUS_IS_OK(status
)) {
434 * We got access denied. If we're already root, or we didn't
435 * need to do a chown, or the fsp isn't open with WRITE_OWNER
436 * access, just return.
439 if ((security_info_sent
& SECINFO_OWNER
) &&
440 (psd
->owner_sid
!= NULL
))
444 if ((security_info_sent
& SECINFO_GROUP
) &&
445 (psd
->group_sid
!= NULL
))
450 if (get_current_uid(handle
->conn
) == 0 ||
451 chown_needed
== false ||
452 !(fsp
->access_mask
& SEC_STD_WRITE_OWNER
))
454 return NT_STATUS_ACCESS_DENIED
;
458 * Only allow take-ownership, not give-ownership. That's the way Windows
459 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
460 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
461 * objectstore, as determined in an implementation specific manner, the
462 * object store MUST return STATUS_INVALID_OWNER.
464 token
= get_current_nttok(fsp
->conn
);
465 if (!security_token_is_sid(token
, psd
->owner_sid
)) {
466 return NT_STATUS_INVALID_OWNER
;
469 DBG_DEBUG("overriding chown on file %s for sid %s\n",
470 fsp_str_dbg(fsp
), sid_string_tos(psd
->owner_sid
));
473 status
= smb_set_nt_acl_nfs4(handle
,
475 &config
->nfs4_params
,
478 nfs4acl_smb4acl_set_fn
);
483 static int nfs4acl_connect(struct vfs_handle_struct
*handle
,
487 struct nfs4acl_config
*config
= NULL
;
488 const struct enum_list
*default_acl_style_list
= NULL
;
489 const char *default_xattr_name
= NULL
;
491 unsigned nfs_version
;
494 default_acl_style_list
= get_default_acl_style_list();
496 config
= talloc_zero(handle
->conn
, struct nfs4acl_config
);
497 if (config
== NULL
) {
498 DBG_ERR("talloc_zero() failed\n");
502 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
508 ret
= smbacl4_get_vfs_params(handle
->conn
, &config
->nfs4_params
);
514 enumval
= lp_parm_enum(SNUM(handle
->conn
),
518 NFS4ACL_ENCODING_NDR
);
520 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
523 config
->encoding
= (enum nfs4acl_encoding
)enumval
;
525 switch (config
->encoding
) {
526 case NFS4ACL_ENCODING_XDR
:
527 default_xattr_name
= NFS4ACL_XDR_XATTR_NAME
;
529 case NFS4ACL_ENCODING_NDR
:
531 default_xattr_name
= NFS4ACL_NDR_XATTR_NAME
;
535 nfs_version
= (unsigned)lp_parm_int(SNUM(handle
->conn
),
539 switch (nfs_version
) {
541 config
->nfs_version
= ACL4_XATTR_VERSION_40
;
544 config
->nfs_version
= ACL4_XATTR_VERSION_41
;
547 config
->nfs_version
= ACL4_XATTR_VERSION_DEFAULT
;
551 config
->default_acl_style
= lp_parm_enum(SNUM(handle
->conn
),
554 default_acl_style_list
,
555 DEFAULT_ACL_EVERYONE
);
557 config
->xattr_name
= lp_parm_talloc_string(config
,
563 SMB_VFS_HANDLE_SET_DATA(handle
, config
, NULL
, struct nfs4acl_config
,
567 * Ensure we have the parameters correct if we're using this module.
569 DBG_NOTICE("Setting 'inherit acls = true', "
570 "'dos filemode = true', "
571 "'force unknown acl user = true', "
572 "'create mask = 0666', "
573 "'directory mask = 0777' and "
574 "'store dos attributes = yes' "
575 "for service [%s]\n", service
);
577 lp_do_parameter(SNUM(handle
->conn
), "inherit acls", "true");
578 lp_do_parameter(SNUM(handle
->conn
), "dos filemode", "true");
579 lp_do_parameter(SNUM(handle
->conn
), "force unknown acl user", "true");
580 lp_do_parameter(SNUM(handle
->conn
), "create mask", "0666");
581 lp_do_parameter(SNUM(handle
->conn
), "directory mask", "0777");
582 lp_do_parameter(SNUM(handle
->conn
), "store dos attributes", "yes");
588 As long as Samba does not support an exiplicit method for a module
589 to define conflicting vfs methods, we should override all conflicting
590 methods here. That way, we know we are using the NFSv4 storage
592 Function declarations taken from vfs_solarisacl
595 static SMB_ACL_T
nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct
*handle
,
596 const struct smb_filename
*smb_fname
,
600 return (SMB_ACL_T
)NULL
;
603 static SMB_ACL_T
nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct
*handle
,
607 return (SMB_ACL_T
)NULL
;
610 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct
*handle
,
611 const struct smb_filename
*smb_fname
,
618 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct
*handle
,
625 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct
*handle
,
626 const struct smb_filename
*smb_fname
)
631 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct
*handle
,
632 const struct smb_filename
*smb_fname
,
634 char **blob_description
,
640 static int nfs4acl_xattr_fail__sys_acl_blob_get_fd(vfs_handle_struct
*handle
, files_struct
*fsp
, TALLOC_CTX
*mem_ctx
, char **blob_description
, DATA_BLOB
*blob
)
645 /* VFS operations structure */
647 static struct vfs_fn_pointers nfs4acl_xattr_fns
= {
648 .connect_fn
= nfs4acl_connect
,
649 .fget_nt_acl_fn
= nfs4acl_xattr_fget_nt_acl
,
650 .get_nt_acl_fn
= nfs4acl_xattr_get_nt_acl
,
651 .fset_nt_acl_fn
= nfs4acl_xattr_fset_nt_acl
,
653 .sys_acl_get_file_fn
= nfs4acl_xattr_fail__sys_acl_get_file
,
654 .sys_acl_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_get_fd
,
655 .sys_acl_blob_get_file_fn
= nfs4acl_xattr_fail__sys_acl_blob_get_file
,
656 .sys_acl_blob_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_blob_get_fd
,
657 .sys_acl_set_file_fn
= nfs4acl_xattr_fail__sys_acl_set_file
,
658 .sys_acl_set_fd_fn
= nfs4acl_xattr_fail__sys_acl_set_fd
,
659 .sys_acl_delete_def_file_fn
= nfs4acl_xattr_fail__sys_acl_delete_def_file
,
663 NTSTATUS
vfs_nfs4acl_xattr_init(TALLOC_CTX
*ctx
)
665 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "nfs4acl_xattr",