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_at(struct vfs_handle_struct
*handle
,
266 struct files_struct
*dirfsp
,
267 const struct smb_filename
*smb_fname
,
268 uint32_t security_info
,
270 struct security_descriptor
**sd
)
272 struct SMB4ACL_T
*smb4acl
= NULL
;
273 TALLOC_CTX
*frame
= talloc_stackframe();
277 SMB_ASSERT(dirfsp
== handle
->conn
->cwd_fsp
);
279 status
= nfs4acl_get_blob(handle
, NULL
, smb_fname
, frame
, &blob
);
280 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
282 return nfs4acl_xattr_default_sd(
283 handle
, smb_fname
, mem_ctx
, sd
);
285 if (!NT_STATUS_IS_OK(status
)) {
290 status
= nfs4acl_blob_to_smb4(handle
, &blob
, frame
, &smb4acl
);
291 if (!NT_STATUS_IS_OK(status
)) {
296 status
= smb_get_nt_acl_nfs4(handle
->conn
, smb_fname
, NULL
,
297 security_info
, mem_ctx
, sd
,
303 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct
*handle
,
305 struct SMB4ACL_T
*smb4acl
)
307 struct nfs4acl_config
*config
= NULL
;
313 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
314 struct nfs4acl_config
,
317 switch (config
->encoding
) {
318 case NFS4ACL_ENCODING_NDR
:
319 status
= nfs4acl_smb4acl_to_ndr_blob(handle
, talloc_tos(),
322 case NFS4ACL_ENCODING_XDR
:
323 status
= nfs4acl_smb4acl_to_xdr_blob(handle
, talloc_tos(),
326 case NFS4ACL_ENCODING_NFS
:
327 status
= nfs4acl_smb4acl_to_nfs_blob(handle
, talloc_tos(),
331 status
= NT_STATUS_INTERNAL_ERROR
;
334 if (!NT_STATUS_IS_OK(status
)) {
338 if (fsp
->fh
->fd
!= -1) {
339 ret
= SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, config
->xattr_name
,
340 blob
.data
, blob
.length
, 0);
342 ret
= SMB_VFS_NEXT_SETXATTR(handle
, fsp
->fsp_name
,
344 blob
.data
, blob
.length
, 0);
349 data_blob_free(&blob
);
350 if (saved_errno
!= 0) {
354 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno
));
361 static NTSTATUS
nfs4acl_xattr_fset_nt_acl(vfs_handle_struct
*handle
,
363 uint32_t security_info_sent
,
364 const struct security_descriptor
*psd
)
366 struct nfs4acl_config
*config
= NULL
;
367 const struct security_token
*token
= NULL
;
368 mode_t existing_mode
;
369 mode_t expected_mode
;
370 mode_t restored_mode
;
371 bool chown_needed
= false;
372 struct dom_sid_buf buf
;
376 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
377 struct nfs4acl_config
,
378 return NT_STATUS_INTERNAL_ERROR
);
380 if (!VALID_STAT(fsp
->fsp_name
->st
)) {
381 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp
));
382 return NT_STATUS_INTERNAL_ERROR
;
385 existing_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
386 if (S_ISDIR(existing_mode
)) {
387 expected_mode
= 0777;
389 expected_mode
= 0666;
391 if (!config
->validate_mode
) {
395 if ((existing_mode
& expected_mode
) != expected_mode
) {
397 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
,
409 DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
410 fsp_str_dbg(fsp
), existing_mode
,
412 return map_nt_error_from_unix(errno
);
416 status
= smb_set_nt_acl_nfs4(handle
,
418 &config
->nfs4_params
,
421 nfs4acl_smb4acl_set_fn
);
422 if (NT_STATUS_IS_OK(status
)) {
425 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
430 * We got access denied. If we're already root, or we didn't
431 * need to do a chown, or the fsp isn't open with WRITE_OWNER
432 * access, just return.
435 if ((security_info_sent
& SECINFO_OWNER
) &&
436 (psd
->owner_sid
!= NULL
))
440 if ((security_info_sent
& SECINFO_GROUP
) &&
441 (psd
->group_sid
!= NULL
))
446 if (get_current_uid(handle
->conn
) == 0 ||
447 chown_needed
== false ||
448 !(fsp
->access_mask
& SEC_STD_WRITE_OWNER
))
450 return NT_STATUS_ACCESS_DENIED
;
454 * Only allow take-ownership, not give-ownership. That's the way Windows
455 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
456 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
457 * objectstore, as determined in an implementation specific manner, the
458 * object store MUST return STATUS_INVALID_OWNER.
460 token
= get_current_nttok(fsp
->conn
);
461 if (!security_token_is_sid(token
, psd
->owner_sid
)) {
462 return NT_STATUS_INVALID_OWNER
;
465 DBG_DEBUG("overriding chown on file %s for sid %s\n",
467 dom_sid_str_buf(psd
->owner_sid
, &buf
));
469 status
= smb_set_nt_acl_nfs4(handle
,
471 &config
->nfs4_params
,
474 nfs4acl_smb4acl_set_fn
);
478 static int nfs4acl_connect(struct vfs_handle_struct
*handle
,
482 const struct loadparm_substitution
*lp_sub
=
483 loadparm_s3_global_substitution();
484 struct nfs4acl_config
*config
= NULL
;
485 const struct enum_list
*default_acl_style_list
= NULL
;
486 const char *default_xattr_name
= NULL
;
487 bool default_validate_mode
= true;
489 unsigned nfs_version
;
492 default_acl_style_list
= get_default_acl_style_list();
494 config
= talloc_zero(handle
->conn
, struct nfs4acl_config
);
495 if (config
== NULL
) {
496 DBG_ERR("talloc_zero() failed\n");
500 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
506 ret
= smbacl4_get_vfs_params(handle
->conn
, &config
->nfs4_params
);
512 enumval
= lp_parm_enum(SNUM(handle
->conn
),
516 NFS4ACL_ENCODING_NDR
);
518 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
521 config
->encoding
= (enum nfs4acl_encoding
)enumval
;
523 switch (config
->encoding
) {
524 case NFS4ACL_ENCODING_XDR
:
525 default_xattr_name
= NFS4ACL_XDR_XATTR_NAME
;
527 case NFS4ACL_ENCODING_NFS
:
528 default_xattr_name
= NFS4ACL_NFS_XATTR_NAME
;
529 default_validate_mode
= false;
531 case NFS4ACL_ENCODING_NDR
:
533 default_xattr_name
= NFS4ACL_NDR_XATTR_NAME
;
537 nfs_version
= (unsigned)lp_parm_int(SNUM(handle
->conn
),
541 switch (nfs_version
) {
543 config
->nfs_version
= ACL4_XATTR_VERSION_40
;
546 config
->nfs_version
= ACL4_XATTR_VERSION_41
;
549 config
->nfs_version
= ACL4_XATTR_VERSION_DEFAULT
;
553 config
->default_acl_style
= lp_parm_enum(SNUM(handle
->conn
),
556 default_acl_style_list
,
557 DEFAULT_ACL_EVERYONE
);
559 config
->xattr_name
= lp_parm_substituted_string(config
, lp_sub
,
565 config
->nfs4_id_numeric
= lp_parm_bool(SNUM(handle
->conn
),
571 config
->validate_mode
= lp_parm_bool(SNUM(handle
->conn
),
574 default_validate_mode
);
576 SMB_VFS_HANDLE_SET_DATA(handle
, config
, NULL
, struct nfs4acl_config
,
580 * Ensure we have the parameters correct if we're using this module.
582 DBG_NOTICE("Setting 'inherit acls = true', "
583 "'dos filemode = true', "
584 "'force unknown acl user = true', "
585 "'create mask = 0666', "
586 "'directory mask = 0777' and "
587 "'store dos attributes = yes' "
588 "for service [%s]\n", service
);
590 lp_do_parameter(SNUM(handle
->conn
), "inherit acls", "true");
591 lp_do_parameter(SNUM(handle
->conn
), "dos filemode", "true");
592 lp_do_parameter(SNUM(handle
->conn
), "force unknown acl user", "true");
593 lp_do_parameter(SNUM(handle
->conn
), "create mask", "0666");
594 lp_do_parameter(SNUM(handle
->conn
), "directory mask", "0777");
595 lp_do_parameter(SNUM(handle
->conn
), "store dos attributes", "yes");
601 As long as Samba does not support an exiplicit method for a module
602 to define conflicting vfs methods, we should override all conflicting
603 methods here. That way, we know we are using the NFSv4 storage
605 Function declarations taken from vfs_solarisacl
608 static SMB_ACL_T
nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct
*handle
,
609 const struct smb_filename
*smb_fname
,
613 return (SMB_ACL_T
)NULL
;
616 static SMB_ACL_T
nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct
*handle
,
620 return (SMB_ACL_T
)NULL
;
623 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct
*handle
,
624 const struct smb_filename
*smb_fname
,
631 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct
*handle
,
638 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct
*handle
,
639 const struct smb_filename
*smb_fname
)
644 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct
*handle
,
645 const struct smb_filename
*smb_fname
,
647 char **blob_description
,
653 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
)
658 /* VFS operations structure */
660 static struct vfs_fn_pointers nfs4acl_xattr_fns
= {
661 .connect_fn
= nfs4acl_connect
,
662 .fget_nt_acl_fn
= nfs4acl_xattr_fget_nt_acl
,
663 .get_nt_acl_at_fn
= nfs4acl_xattr_get_nt_acl_at
,
664 .fset_nt_acl_fn
= nfs4acl_xattr_fset_nt_acl
,
666 .sys_acl_get_file_fn
= nfs4acl_xattr_fail__sys_acl_get_file
,
667 .sys_acl_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_get_fd
,
668 .sys_acl_blob_get_file_fn
= nfs4acl_xattr_fail__sys_acl_blob_get_file
,
669 .sys_acl_blob_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_blob_get_fd
,
670 .sys_acl_set_file_fn
= nfs4acl_xattr_fail__sys_acl_set_file
,
671 .sys_acl_set_fd_fn
= nfs4acl_xattr_fail__sys_acl_set_fd
,
672 .sys_acl_delete_def_file_fn
= nfs4acl_xattr_fail__sys_acl_delete_def_file
,
676 NTSTATUS
vfs_nfs4acl_xattr_init(TALLOC_CTX
*ctx
)
678 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "nfs4acl_xattr",