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 "libcli/security/dom_sid.h"
34 #include "nfs4_acls.h"
35 #include "librpc/gen_ndr/ndr_nfs4acl.h"
36 #include "nfs4acl_xattr.h"
37 #include "nfs4acl_xattr_ndr.h"
38 #include "nfs4acl_xattr_xdr.h"
39 #include "nfs4acl_xattr_nfs.h"
42 #define DBGC_CLASS DBGC_VFS
44 static const struct enum_list nfs4acl_encoding
[] = {
45 {NFS4ACL_ENCODING_NDR
, "ndr"},
46 {NFS4ACL_ENCODING_XDR
, "xdr"},
47 {NFS4ACL_ENCODING_NFS
, "nfs"},
51 * Check if someone changed the POSIX mode, for files we expect 0666, for
52 * directories 0777. Discard the ACL blob if the mode is different.
54 static bool nfs4acl_validate_blob(vfs_handle_struct
*handle
,
55 const struct smb_filename
*smb_fname
)
57 struct nfs4acl_config
*config
= NULL
;
61 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
62 struct nfs4acl_config
,
65 if (!config
->validate_mode
) {
69 if (!VALID_STAT(smb_fname
->st
)) {
70 /* might be a create */
74 if (S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
79 if ((smb_fname
->st
.st_ex_mode
& expected_mode
) == expected_mode
) {
83 ret
= SMB_VFS_NEXT_REMOVEXATTR(handle
,
86 if (ret
!= 0 && errno
!= ENOATTR
) {
87 DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno
));
94 static NTSTATUS
nfs4acl_get_blob(struct vfs_handle_struct
*handle
,
96 const struct smb_filename
*smb_fname_in
,
100 struct nfs4acl_config
*config
= NULL
;
101 const struct smb_filename
*smb_fname
= NULL
;
102 size_t allocsize
= 256;
106 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
107 struct nfs4acl_config
,
108 return NT_STATUS_INTERNAL_ERROR
);
110 *blob
= data_blob_null
;
112 if (fsp
== NULL
&& smb_fname_in
== NULL
) {
113 return NT_STATUS_INTERNAL_ERROR
;
115 smb_fname
= smb_fname_in
;
116 if (smb_fname
== NULL
) {
117 smb_fname
= fsp
->fsp_name
;
119 if (smb_fname
== NULL
) {
120 return NT_STATUS_INTERNAL_ERROR
;
123 ok
= nfs4acl_validate_blob(handle
, smb_fname
);
125 return NT_STATUS_INTERNAL_ERROR
;
131 ok
= data_blob_realloc(mem_ctx
, blob
, allocsize
);
133 return NT_STATUS_NO_MEMORY
;
136 if (fsp
!= NULL
&& fsp
->fh
->fd
!= -1) {
137 length
= SMB_VFS_NEXT_FGETXATTR(handle
,
143 length
= SMB_VFS_NEXT_GETXATTR(handle
,
149 } while (length
== -1 && errno
== ERANGE
&& allocsize
<= 65536);
152 return map_nt_error_from_unix(errno
);
158 static NTSTATUS
nfs4acl_xattr_default_sd(
159 struct vfs_handle_struct
*handle
,
160 const struct smb_filename
*smb_fname
,
162 struct security_descriptor
**sd
)
164 struct nfs4acl_config
*config
= NULL
;
165 enum default_acl_style default_acl_style
;
166 mode_t required_mode
;
167 SMB_STRUCT_STAT sbuf
= smb_fname
->st
;
170 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
171 struct nfs4acl_config
,
172 return NT_STATUS_INTERNAL_ERROR
);
174 default_acl_style
= config
->default_acl_style
;
176 if (!VALID_STAT(sbuf
)) {
177 ret
= vfs_stat_smb_basename(handle
->conn
,
181 return map_nt_error_from_unix(errno
);
185 if (S_ISDIR(sbuf
.st_ex_mode
)) {
186 required_mode
= 0777;
188 required_mode
= 0666;
190 if ((sbuf
.st_ex_mode
& required_mode
) != required_mode
) {
191 default_acl_style
= DEFAULT_ACL_POSIX
;
194 return make_default_filesystem_acl(mem_ctx
,
196 smb_fname
->base_name
,
201 static NTSTATUS
nfs4acl_blob_to_smb4(struct vfs_handle_struct
*handle
,
204 struct SMB4ACL_T
**smb4acl
)
206 struct nfs4acl_config
*config
= NULL
;
209 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
210 struct nfs4acl_config
,
211 return NT_STATUS_INTERNAL_ERROR
);
213 switch (config
->encoding
) {
214 case NFS4ACL_ENCODING_NDR
:
215 status
= nfs4acl_ndr_blob_to_smb4(handle
, mem_ctx
, blob
, smb4acl
);
217 case NFS4ACL_ENCODING_XDR
:
218 status
= nfs4acl_xdr_blob_to_smb4(handle
, mem_ctx
, blob
, smb4acl
);
220 case NFS4ACL_ENCODING_NFS
:
221 status
= nfs4acl_nfs_blob_to_smb4(handle
, mem_ctx
, blob
, smb4acl
);
224 status
= NT_STATUS_INTERNAL_ERROR
;
231 static NTSTATUS
nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct
*handle
,
232 struct files_struct
*fsp
,
233 uint32_t security_info
,
235 struct security_descriptor
**sd
)
237 struct SMB4ACL_T
*smb4acl
= NULL
;
238 TALLOC_CTX
*frame
= talloc_stackframe();
242 status
= nfs4acl_get_blob(handle
, fsp
, NULL
, frame
, &blob
);
243 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
245 return nfs4acl_xattr_default_sd(
246 handle
, fsp
->fsp_name
, mem_ctx
, sd
);
248 if (!NT_STATUS_IS_OK(status
)) {
253 status
= nfs4acl_blob_to_smb4(handle
, &blob
, frame
, &smb4acl
);
254 if (!NT_STATUS_IS_OK(status
)) {
259 status
= smb_fget_nt_acl_nfs4(fsp
, NULL
, security_info
, mem_ctx
,
265 static NTSTATUS
nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct
*handle
,
266 const struct smb_filename
*smb_fname
,
267 uint32_t security_info
,
269 struct security_descriptor
**sd
)
271 struct SMB4ACL_T
*smb4acl
= NULL
;
272 TALLOC_CTX
*frame
= talloc_stackframe();
276 status
= nfs4acl_get_blob(handle
, NULL
, smb_fname
, frame
, &blob
);
277 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
279 return nfs4acl_xattr_default_sd(
280 handle
, smb_fname
, mem_ctx
, sd
);
282 if (!NT_STATUS_IS_OK(status
)) {
287 status
= nfs4acl_blob_to_smb4(handle
, &blob
, frame
, &smb4acl
);
288 if (!NT_STATUS_IS_OK(status
)) {
293 status
= smb_get_nt_acl_nfs4(handle
->conn
, smb_fname
, NULL
,
294 security_info
, mem_ctx
, sd
,
300 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct
*handle
,
302 struct SMB4ACL_T
*smb4acl
)
304 struct nfs4acl_config
*config
= NULL
;
310 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
311 struct nfs4acl_config
,
314 switch (config
->encoding
) {
315 case NFS4ACL_ENCODING_NDR
:
316 status
= nfs4acl_smb4acl_to_ndr_blob(handle
, talloc_tos(),
319 case NFS4ACL_ENCODING_XDR
:
320 status
= nfs4acl_smb4acl_to_xdr_blob(handle
, talloc_tos(),
323 case NFS4ACL_ENCODING_NFS
:
324 status
= nfs4acl_smb4acl_to_nfs_blob(handle
, talloc_tos(),
328 status
= NT_STATUS_INTERNAL_ERROR
;
331 if (!NT_STATUS_IS_OK(status
)) {
335 if (fsp
->fh
->fd
!= -1) {
336 ret
= SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, config
->xattr_name
,
337 blob
.data
, blob
.length
, 0);
339 ret
= SMB_VFS_NEXT_SETXATTR(handle
, fsp
->fsp_name
,
341 blob
.data
, blob
.length
, 0);
346 data_blob_free(&blob
);
347 if (saved_errno
!= 0) {
351 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno
));
358 static NTSTATUS
nfs4acl_xattr_fset_nt_acl(vfs_handle_struct
*handle
,
360 uint32_t security_info_sent
,
361 const struct security_descriptor
*psd
)
363 struct nfs4acl_config
*config
= NULL
;
364 const struct security_token
*token
= NULL
;
365 mode_t existing_mode
;
366 mode_t expected_mode
;
367 mode_t restored_mode
;
368 bool chown_needed
= false;
369 struct dom_sid_buf buf
;
373 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
374 struct nfs4acl_config
,
375 return NT_STATUS_INTERNAL_ERROR
);
377 if (!VALID_STAT(fsp
->fsp_name
->st
)) {
378 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp
));
379 return NT_STATUS_INTERNAL_ERROR
;
382 existing_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
383 if (S_ISDIR(existing_mode
)) {
384 expected_mode
= 0777;
386 expected_mode
= 0666;
388 if (!config
->validate_mode
) {
392 if ((existing_mode
& expected_mode
) != expected_mode
) {
394 restored_mode
= existing_mode
| expected_mode
;
396 if (fsp
->fh
->fd
!= -1) {
397 ret
= SMB_VFS_NEXT_FCHMOD(handle
,
401 ret
= SMB_VFS_NEXT_CHMOD(handle
,
406 DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
407 fsp_str_dbg(fsp
), existing_mode
,
409 return map_nt_error_from_unix(errno
);
413 status
= smb_set_nt_acl_nfs4(handle
,
415 &config
->nfs4_params
,
418 nfs4acl_smb4acl_set_fn
);
419 if (NT_STATUS_IS_OK(status
)) {
422 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
427 * We got access denied. If we're already root, or we didn't
428 * need to do a chown, or the fsp isn't open with WRITE_OWNER
429 * access, just return.
432 if ((security_info_sent
& SECINFO_OWNER
) &&
433 (psd
->owner_sid
!= NULL
))
437 if ((security_info_sent
& SECINFO_GROUP
) &&
438 (psd
->group_sid
!= NULL
))
443 if (get_current_uid(handle
->conn
) == 0 ||
444 chown_needed
== false ||
445 !(fsp
->access_mask
& SEC_STD_WRITE_OWNER
))
447 return NT_STATUS_ACCESS_DENIED
;
451 * Only allow take-ownership, not give-ownership. That's the way Windows
452 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
453 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
454 * objectstore, as determined in an implementation specific manner, the
455 * object store MUST return STATUS_INVALID_OWNER.
457 token
= get_current_nttok(fsp
->conn
);
458 if (!security_token_is_sid(token
, psd
->owner_sid
)) {
459 return NT_STATUS_INVALID_OWNER
;
462 DBG_DEBUG("overriding chown on file %s for sid %s\n",
464 dom_sid_str_buf(psd
->owner_sid
, &buf
));
466 status
= smb_set_nt_acl_nfs4(handle
,
468 &config
->nfs4_params
,
471 nfs4acl_smb4acl_set_fn
);
475 static int nfs4acl_connect(struct vfs_handle_struct
*handle
,
479 const struct loadparm_substitution
*lp_sub
=
480 loadparm_s3_global_substitution();
481 struct nfs4acl_config
*config
= NULL
;
482 const struct enum_list
*default_acl_style_list
= NULL
;
483 const char *default_xattr_name
= NULL
;
484 bool default_validate_mode
= true;
486 unsigned nfs_version
;
489 default_acl_style_list
= get_default_acl_style_list();
491 config
= talloc_zero(handle
->conn
, struct nfs4acl_config
);
492 if (config
== NULL
) {
493 DBG_ERR("talloc_zero() failed\n");
497 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
503 ret
= smbacl4_get_vfs_params(handle
->conn
, &config
->nfs4_params
);
509 enumval
= lp_parm_enum(SNUM(handle
->conn
),
513 NFS4ACL_ENCODING_NDR
);
515 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
518 config
->encoding
= (enum nfs4acl_encoding
)enumval
;
520 switch (config
->encoding
) {
521 case NFS4ACL_ENCODING_XDR
:
522 default_xattr_name
= NFS4ACL_XDR_XATTR_NAME
;
524 case NFS4ACL_ENCODING_NFS
:
525 default_xattr_name
= NFS4ACL_NFS_XATTR_NAME
;
526 default_validate_mode
= false;
528 case NFS4ACL_ENCODING_NDR
:
530 default_xattr_name
= NFS4ACL_NDR_XATTR_NAME
;
534 nfs_version
= (unsigned)lp_parm_int(SNUM(handle
->conn
),
538 switch (nfs_version
) {
540 config
->nfs_version
= ACL4_XATTR_VERSION_40
;
543 config
->nfs_version
= ACL4_XATTR_VERSION_41
;
546 config
->nfs_version
= ACL4_XATTR_VERSION_DEFAULT
;
550 config
->default_acl_style
= lp_parm_enum(SNUM(handle
->conn
),
553 default_acl_style_list
,
554 DEFAULT_ACL_EVERYONE
);
556 config
->xattr_name
= lp_parm_substituted_string(config
, lp_sub
,
562 config
->nfs4_id_numeric
= lp_parm_bool(SNUM(handle
->conn
),
568 config
->validate_mode
= lp_parm_bool(SNUM(handle
->conn
),
571 default_validate_mode
);
573 SMB_VFS_HANDLE_SET_DATA(handle
, config
, NULL
, struct nfs4acl_config
,
577 * Ensure we have the parameters correct if we're using this module.
579 DBG_NOTICE("Setting 'inherit acls = true', "
580 "'dos filemode = true', "
581 "'force unknown acl user = true', "
582 "'create mask = 0666', "
583 "'directory mask = 0777' and "
584 "'store dos attributes = yes' "
585 "for service [%s]\n", service
);
587 lp_do_parameter(SNUM(handle
->conn
), "inherit acls", "true");
588 lp_do_parameter(SNUM(handle
->conn
), "dos filemode", "true");
589 lp_do_parameter(SNUM(handle
->conn
), "force unknown acl user", "true");
590 lp_do_parameter(SNUM(handle
->conn
), "create mask", "0666");
591 lp_do_parameter(SNUM(handle
->conn
), "directory mask", "0777");
592 lp_do_parameter(SNUM(handle
->conn
), "store dos attributes", "yes");
598 As long as Samba does not support an exiplicit method for a module
599 to define conflicting vfs methods, we should override all conflicting
600 methods here. That way, we know we are using the NFSv4 storage
602 Function declarations taken from vfs_solarisacl
605 static SMB_ACL_T
nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct
*handle
,
606 const struct smb_filename
*smb_fname
,
610 return (SMB_ACL_T
)NULL
;
613 static SMB_ACL_T
nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct
*handle
,
617 return (SMB_ACL_T
)NULL
;
620 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct
*handle
,
621 const struct smb_filename
*smb_fname
,
628 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct
*handle
,
635 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct
*handle
,
636 const struct smb_filename
*smb_fname
)
641 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct
*handle
,
642 const struct smb_filename
*smb_fname
,
644 char **blob_description
,
650 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
)
655 /* VFS operations structure */
657 static struct vfs_fn_pointers nfs4acl_xattr_fns
= {
658 .connect_fn
= nfs4acl_connect
,
659 .fget_nt_acl_fn
= nfs4acl_xattr_fget_nt_acl
,
660 .get_nt_acl_fn
= nfs4acl_xattr_get_nt_acl
,
661 .fset_nt_acl_fn
= nfs4acl_xattr_fset_nt_acl
,
663 .sys_acl_get_file_fn
= nfs4acl_xattr_fail__sys_acl_get_file
,
664 .sys_acl_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_get_fd
,
665 .sys_acl_blob_get_file_fn
= nfs4acl_xattr_fail__sys_acl_blob_get_file
,
666 .sys_acl_blob_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_blob_get_fd
,
667 .sys_acl_set_file_fn
= nfs4acl_xattr_fail__sys_acl_set_file
,
668 .sys_acl_set_fd_fn
= nfs4acl_xattr_fail__sys_acl_set_fd
,
669 .sys_acl_delete_def_file_fn
= nfs4acl_xattr_fail__sys_acl_delete_def_file
,
673 NTSTATUS
vfs_nfs4acl_xattr_init(TALLOC_CTX
*ctx
)
675 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "nfs4acl_xattr",