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 ||
372 !(fsp
->access_mask
& SEC_STD_WRITE_OWNER
))
374 return NT_STATUS_ACCESS_DENIED
;
378 * Only allow take-ownership, not give-ownership. That's the way Windows
379 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
380 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
381 * objectstore, as determined in an implementation specific manner, the
382 * object store MUST return STATUS_INVALID_OWNER.
384 token
= get_current_nttok(fsp
->conn
);
385 if (!security_token_is_sid(token
, psd
->owner_sid
)) {
386 return NT_STATUS_INVALID_OWNER
;
389 DBG_DEBUG("overriding chown on file %s for sid %s\n",
391 dom_sid_str_buf(psd
->owner_sid
, &buf
));
393 status
= smb_set_nt_acl_nfs4(handle
,
395 &config
->nfs4_params
,
398 nfs4acl_smb4acl_set_fn
);
402 static int nfs4acl_connect(struct vfs_handle_struct
*handle
,
406 const struct loadparm_substitution
*lp_sub
=
407 loadparm_s3_global_substitution();
408 struct nfs4acl_config
*config
= NULL
;
409 const struct enum_list
*default_acl_style_list
= NULL
;
410 const char *default_xattr_name
= NULL
;
411 bool default_validate_mode
= true;
413 unsigned nfs_version
;
416 default_acl_style_list
= get_default_acl_style_list();
418 config
= talloc_zero(handle
->conn
, struct nfs4acl_config
);
419 if (config
== NULL
) {
420 DBG_ERR("talloc_zero() failed\n");
424 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
430 ret
= smbacl4_get_vfs_params(handle
->conn
, &config
->nfs4_params
);
436 enumval
= lp_parm_enum(SNUM(handle
->conn
),
440 NFS4ACL_ENCODING_NDR
);
442 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
445 config
->encoding
= (enum nfs4acl_encoding
)enumval
;
447 switch (config
->encoding
) {
448 case NFS4ACL_ENCODING_XDR
:
449 default_xattr_name
= NFS4ACL_XDR_XATTR_NAME
;
451 case NFS4ACL_ENCODING_NFS
:
452 default_xattr_name
= NFS4ACL_NFS_XATTR_NAME
;
453 default_validate_mode
= false;
455 case NFS4ACL_ENCODING_NDR
:
457 default_xattr_name
= NFS4ACL_NDR_XATTR_NAME
;
461 nfs_version
= (unsigned)lp_parm_int(SNUM(handle
->conn
),
465 switch (nfs_version
) {
467 config
->nfs_version
= ACL4_XATTR_VERSION_40
;
470 config
->nfs_version
= ACL4_XATTR_VERSION_41
;
473 config
->nfs_version
= ACL4_XATTR_VERSION_DEFAULT
;
477 config
->default_acl_style
= lp_parm_enum(SNUM(handle
->conn
),
480 default_acl_style_list
,
481 DEFAULT_ACL_EVERYONE
);
483 config
->xattr_name
= lp_parm_substituted_string(config
, lp_sub
,
489 config
->nfs4_id_numeric
= lp_parm_bool(SNUM(handle
->conn
),
495 config
->validate_mode
= lp_parm_bool(SNUM(handle
->conn
),
498 default_validate_mode
);
500 SMB_VFS_HANDLE_SET_DATA(handle
, config
, NULL
, struct nfs4acl_config
,
504 * Ensure we have the parameters correct if we're using this module.
506 DBG_NOTICE("Setting 'inherit acls = true', "
507 "'dos filemode = true', "
508 "'force unknown acl user = true', "
509 "'create mask = 0666', "
510 "'directory mask = 0777' and "
511 "'store dos attributes = yes' "
512 "for service [%s]\n", service
);
514 lp_do_parameter(SNUM(handle
->conn
), "inherit acls", "true");
515 lp_do_parameter(SNUM(handle
->conn
), "dos filemode", "true");
516 lp_do_parameter(SNUM(handle
->conn
), "force unknown acl user", "true");
517 lp_do_parameter(SNUM(handle
->conn
), "create mask", "0666");
518 lp_do_parameter(SNUM(handle
->conn
), "directory mask", "0777");
519 lp_do_parameter(SNUM(handle
->conn
), "store dos attributes", "yes");
525 As long as Samba does not support an exiplicit method for a module
526 to define conflicting vfs methods, we should override all conflicting
527 methods here. That way, we know we are using the NFSv4 storage
529 Function declarations taken from vfs_solarisacl
532 static SMB_ACL_T
nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct
*handle
,
537 return (SMB_ACL_T
)NULL
;
540 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct
*handle
,
548 static int nfs4acl_xattr_fail__sys_acl_delete_def_fd(vfs_handle_struct
*handle
,
554 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
)
559 /* VFS operations structure */
561 static struct vfs_fn_pointers nfs4acl_xattr_fns
= {
562 .connect_fn
= nfs4acl_connect
,
563 .fget_nt_acl_fn
= nfs4acl_xattr_fget_nt_acl
,
564 .fset_nt_acl_fn
= nfs4acl_xattr_fset_nt_acl
,
566 .sys_acl_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_get_fd
,
567 .sys_acl_blob_get_fd_fn
= nfs4acl_xattr_fail__sys_acl_blob_get_fd
,
568 .sys_acl_set_fd_fn
= nfs4acl_xattr_fail__sys_acl_set_fd
,
569 .sys_acl_delete_def_fd_fn
= nfs4acl_xattr_fail__sys_acl_delete_def_fd
,
573 NTSTATUS
vfs_nfs4acl_xattr_init(TALLOC_CTX
*ctx
)
575 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "nfs4acl_xattr",