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
,
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 (S_ISDIR(fsp
->fsp_name
->st
.st_ex_mode
)) {
74 if ((fsp
->fsp_name
->st
.st_ex_mode
& expected_mode
) == expected_mode
) {
78 ret
= SMB_VFS_NEXT_FREMOVEXATTR(handle
,
81 if (ret
!= 0 && errno
!= ENOATTR
) {
82 DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno
));
89 static NTSTATUS
nfs4acl_get_blob(struct vfs_handle_struct
*handle
,
94 struct nfs4acl_config
*config
= NULL
;
95 size_t allocsize
= 256;
99 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
100 struct nfs4acl_config
,
101 return NT_STATUS_INTERNAL_ERROR
);
103 *blob
= data_blob_null
;
105 ok
= nfs4acl_validate_blob(handle
, fsp
);
107 return NT_STATUS_INTERNAL_ERROR
;
113 ok
= data_blob_realloc(mem_ctx
, blob
, allocsize
);
115 return NT_STATUS_NO_MEMORY
;
118 length
= SMB_VFS_NEXT_FGETXATTR(handle
,
123 } while (length
== -1 && errno
== ERANGE
&& allocsize
<= 65536);
126 return map_nt_error_from_unix(errno
);
132 static NTSTATUS
nfs4acl_xattr_default_sd(
133 struct vfs_handle_struct
*handle
,
134 const struct smb_filename
*smb_fname
,
136 struct security_descriptor
**sd
)
138 struct nfs4acl_config
*config
= NULL
;
139 enum default_acl_style default_acl_style
;
140 mode_t required_mode
;
141 SMB_STRUCT_STAT sbuf
= smb_fname
->st
;
144 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
145 struct nfs4acl_config
,
146 return NT_STATUS_INTERNAL_ERROR
);
148 default_acl_style
= config
->default_acl_style
;
150 if (!VALID_STAT(sbuf
)) {
151 ret
= vfs_stat_smb_basename(handle
->conn
,
155 return map_nt_error_from_unix(errno
);
159 if (S_ISDIR(sbuf
.st_ex_mode
)) {
160 required_mode
= 0777;
162 required_mode
= 0666;
164 if ((sbuf
.st_ex_mode
& required_mode
) != required_mode
) {
165 default_acl_style
= DEFAULT_ACL_POSIX
;
168 return make_default_filesystem_acl(mem_ctx
,
170 smb_fname
->base_name
,
175 static NTSTATUS
nfs4acl_blob_to_smb4(struct vfs_handle_struct
*handle
,
178 struct SMB4ACL_T
**smb4acl
)
180 struct nfs4acl_config
*config
= NULL
;
183 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
184 struct nfs4acl_config
,
185 return NT_STATUS_INTERNAL_ERROR
);
187 switch (config
->encoding
) {
188 case NFS4ACL_ENCODING_NDR
:
189 status
= nfs4acl_ndr_blob_to_smb4(handle
, mem_ctx
, blob
, smb4acl
);
191 case NFS4ACL_ENCODING_XDR
:
192 status
= nfs4acl_xdr_blob_to_smb4(handle
, mem_ctx
, blob
, smb4acl
);
194 case NFS4ACL_ENCODING_NFS
:
195 status
= nfs4acl_nfs_blob_to_smb4(handle
, mem_ctx
, blob
, smb4acl
);
198 status
= NT_STATUS_INTERNAL_ERROR
;
205 static NTSTATUS
nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct
*handle
,
206 struct files_struct
*fsp
,
207 uint32_t security_info
,
209 struct security_descriptor
**sd
)
211 struct SMB4ACL_T
*smb4acl
= NULL
;
212 TALLOC_CTX
*frame
= talloc_stackframe();
216 status
= nfs4acl_get_blob(handle
, fsp
, frame
, &blob
);
217 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
219 return nfs4acl_xattr_default_sd(
220 handle
, fsp
->fsp_name
, mem_ctx
, sd
);
222 if (!NT_STATUS_IS_OK(status
)) {
227 status
= nfs4acl_blob_to_smb4(handle
, &blob
, frame
, &smb4acl
);
228 if (!NT_STATUS_IS_OK(status
)) {
233 status
= smb_fget_nt_acl_nfs4(fsp
, NULL
, security_info
, mem_ctx
,
239 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct
*handle
,
241 struct SMB4ACL_T
*smb4acl
)
243 struct nfs4acl_config
*config
= NULL
;
249 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
250 struct nfs4acl_config
,
253 switch (config
->encoding
) {
254 case NFS4ACL_ENCODING_NDR
:
255 status
= nfs4acl_smb4acl_to_ndr_blob(handle
, talloc_tos(),
258 case NFS4ACL_ENCODING_XDR
:
259 status
= nfs4acl_smb4acl_to_xdr_blob(handle
, talloc_tos(),
262 case NFS4ACL_ENCODING_NFS
:
263 status
= nfs4acl_smb4acl_to_nfs_blob(handle
, talloc_tos(),
267 status
= NT_STATUS_INTERNAL_ERROR
;
270 if (!NT_STATUS_IS_OK(status
)) {
274 ret
= SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, config
->xattr_name
,
275 blob
.data
, blob
.length
, 0);
279 data_blob_free(&blob
);
280 if (saved_errno
!= 0) {
284 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno
));
291 static NTSTATUS
nfs4acl_xattr_fset_nt_acl(vfs_handle_struct
*handle
,
293 uint32_t security_info_sent
,
294 const struct security_descriptor
*psd
)
296 struct nfs4acl_config
*config
= NULL
;
297 const struct security_token
*token
= NULL
;
298 mode_t existing_mode
;
299 mode_t expected_mode
;
300 mode_t restored_mode
;
301 bool chown_needed
= false;
302 struct dom_sid_buf buf
;
306 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
307 struct nfs4acl_config
,
308 return NT_STATUS_INTERNAL_ERROR
);
310 if (!VALID_STAT(fsp
->fsp_name
->st
)) {
311 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp
));
312 return NT_STATUS_INTERNAL_ERROR
;
315 existing_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
316 if (S_ISDIR(existing_mode
)) {
317 expected_mode
= 0777;
319 expected_mode
= 0666;
321 if (!config
->validate_mode
) {
325 if ((existing_mode
& expected_mode
) != expected_mode
) {
327 restored_mode
= existing_mode
| expected_mode
;
329 ret
= SMB_VFS_NEXT_FCHMOD(handle
,
333 DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
334 fsp_str_dbg(fsp
), existing_mode
,
336 return map_nt_error_from_unix(errno
);
340 status
= smb_set_nt_acl_nfs4(handle
,
342 &config
->nfs4_params
,
345 nfs4acl_smb4acl_set_fn
);
346 if (NT_STATUS_IS_OK(status
)) {
349 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
354 * We got access denied. If we're already root, or we didn't
355 * need to do a chown, or the fsp isn't open with WRITE_OWNER
356 * access, just return.
359 if ((security_info_sent
& SECINFO_OWNER
) &&
360 (psd
->owner_sid
!= NULL
))
364 if ((security_info_sent
& SECINFO_GROUP
) &&
365 (psd
->group_sid
!= NULL
))
370 if (get_current_uid(handle
->conn
) == 0 ||
371 chown_needed
== false)
373 return NT_STATUS_ACCESS_DENIED
;
375 status
= check_any_access_fsp(fsp
, SEC_STD_WRITE_OWNER
);
376 if (!NT_STATUS_IS_OK(status
)) {
381 * Only allow take-ownership, not give-ownership. That's the way Windows
382 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
383 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
384 * objectstore, as determined in an implementation specific manner, the
385 * object store MUST return STATUS_INVALID_OWNER.
387 token
= get_current_nttok(fsp
->conn
);
388 if (!security_token_is_sid(token
, psd
->owner_sid
)) {
389 return NT_STATUS_INVALID_OWNER
;
392 DBG_DEBUG("overriding chown on file %s for sid %s\n",
394 dom_sid_str_buf(psd
->owner_sid
, &buf
));
396 status
= smb_set_nt_acl_nfs4(handle
,
398 &config
->nfs4_params
,
401 nfs4acl_smb4acl_set_fn
);
405 static int nfs4acl_connect(struct vfs_handle_struct
*handle
,
409 const struct loadparm_substitution
*lp_sub
=
410 loadparm_s3_global_substitution();
411 struct nfs4acl_config
*config
= NULL
;
412 const struct enum_list
*default_acl_style_list
= NULL
;
413 const char *default_xattr_name
= NULL
;
414 bool default_validate_mode
= true;
416 unsigned nfs_version
;
419 default_acl_style_list
= get_default_acl_style_list();
421 config
= talloc_zero(handle
->conn
, struct nfs4acl_config
);
422 if (config
== NULL
) {
423 DBG_ERR("talloc_zero() failed\n");
427 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
433 ret
= smbacl4_get_vfs_params(handle
->conn
, &config
->nfs4_params
);
439 enumval
= lp_parm_enum(SNUM(handle
->conn
),
443 NFS4ACL_ENCODING_NDR
);
445 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
448 config
->encoding
= (enum nfs4acl_encoding
)enumval
;
450 switch (config
->encoding
) {
451 case NFS4ACL_ENCODING_XDR
:
452 default_xattr_name
= NFS4ACL_XDR_XATTR_NAME
;
454 case NFS4ACL_ENCODING_NFS
:
455 default_xattr_name
= NFS4ACL_NFS_XATTR_NAME
;
456 default_validate_mode
= false;
458 case NFS4ACL_ENCODING_NDR
:
460 default_xattr_name
= NFS4ACL_NDR_XATTR_NAME
;
464 nfs_version
= (unsigned)lp_parm_int(SNUM(handle
->conn
),
468 switch (nfs_version
) {
470 config
->nfs_version
= ACL4_XATTR_VERSION_40
;
473 config
->nfs_version
= ACL4_XATTR_VERSION_41
;
476 config
->nfs_version
= ACL4_XATTR_VERSION_DEFAULT
;
480 config
->default_acl_style
= lp_parm_enum(SNUM(handle
->conn
),
483 default_acl_style_list
,
484 DEFAULT_ACL_EVERYONE
);
486 config
->xattr_name
= lp_parm_substituted_string(config
, lp_sub
,
492 config
->nfs4_id_numeric
= lp_parm_bool(SNUM(handle
->conn
),
498 config
->validate_mode
= lp_parm_bool(SNUM(handle
->conn
),
501 default_validate_mode
);
503 SMB_VFS_HANDLE_SET_DATA(handle
, config
, NULL
, struct nfs4acl_config
,
507 * Ensure we have the parameters correct if we're using this module.
509 DBG_NOTICE("Setting 'inherit acls = true', "
510 "'dos filemode = true', "
511 "'force unknown acl user = true', "
512 "'create mask = 0666', "
513 "'directory mask = 0777' and "
514 "'store dos attributes = yes' "
515 "for service [%s]\n", service
);
517 lp_do_parameter(SNUM(handle
->conn
), "inherit acls", "true");
518 lp_do_parameter(SNUM(handle
->conn
), "dos filemode", "true");
519 lp_do_parameter(SNUM(handle
->conn
), "force unknown acl user", "true");
520 lp_do_parameter(SNUM(handle
->conn
), "create mask", "0666");
521 lp_do_parameter(SNUM(handle
->conn
), "directory mask", "0777");
522 lp_do_parameter(SNUM(handle
->conn
), "store dos attributes", "yes");
528 As long as Samba does not support an exiplicit method for a module
529 to define conflicting vfs methods, we should override all conflicting
530 methods here. That way, we know we are using the NFSv4 storage
532 Function declarations taken from vfs_solarisacl
535 static SMB_ACL_T
nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct
*handle
,
540 return (SMB_ACL_T
)NULL
;
543 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct
*handle
,
551 static int nfs4acl_xattr_fail__sys_acl_delete_def_fd(vfs_handle_struct
*handle
,
557 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
)
562 /* VFS operations structure */
564 static struct vfs_fn_pointers nfs4acl_xattr_fns
= {
565 .connect_fn
= nfs4acl_connect
,
566 .fget_nt_acl_fn
= nfs4acl_xattr_fget_nt_acl
,
567 .fset_nt_acl_fn
= nfs4acl_xattr_fset_nt_acl
,
569 .sys_acl_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_get_fd
,
570 .sys_acl_blob_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_blob_get_fd
,
571 .sys_acl_set_fd_fn
= nfs4acl_xattr_fail__sys_acl_set_fd
,
572 .sys_acl_delete_def_fd_fn
= nfs4acl_xattr_fail__sys_acl_delete_def_fd
,
576 NTSTATUS
vfs_nfs4acl_xattr_init(TALLOC_CTX
*ctx
)
578 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "nfs4acl_xattr",