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 "nfs4_acls.h"
33 #include "librpc/gen_ndr/ndr_nfs4acl.h"
34 #include "nfs4acl_xattr.h"
37 #define DBGC_CLASS DBGC_VFS
39 static const struct enum_list nfs4acl_encoding[] = {
40 {NFS4ACL_ENCODING_NDR, "ndr"},
41 {NFS4ACL_ENCODING_XDR, "xdr"},
44 static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
46 enum ndr_err_code ndr_err;
47 struct nfs4acl *acl = talloc(mem_ctx, struct nfs4acl);
53 ndr_err = ndr_pull_struct_blob(blob, acl, acl,
54 (ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
56 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
57 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
58 ndr_errstr(ndr_err)));
65 static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
67 enum ndr_err_code ndr_err;
69 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
70 (ndr_push_flags_fn_t)ndr_push_nfs4acl);
72 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
73 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
74 ndr_errstr(ndr_err)));
75 return data_blob_null;
80 static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
82 struct SMB4ACL_T **ppacl)
85 struct nfs4acl *nfs4acl = NULL;
86 struct SMB4ACL_T *pacl = NULL;
87 TALLOC_CTX *frame = talloc_stackframe();
88 nfs4acl = nfs4acl_blob2acl(blob, frame);
90 /* create SMB4ACL data */
91 if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
93 return NT_STATUS_NO_MEMORY;
95 for(i=0; i<nfs4acl->a_count; i++) {
96 SMB_ACE4PROP_T aceprop;
98 aceprop.aceType = (uint32_t) nfs4acl->ace[i].e_type;
99 aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
100 aceprop.aceMask = (uint32_t) nfs4acl->ace[i].e_mask;
101 aceprop.who.id = (uint32_t) nfs4acl->ace[i].e_id;
102 if (!strcmp(nfs4acl->ace[i].e_who,
103 NFS4ACL_XATTR_OWNER_WHO)) {
104 aceprop.flags = SMB_ACE4_ID_SPECIAL;
105 aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
106 } else if (!strcmp(nfs4acl->ace[i].e_who,
107 NFS4ACL_XATTR_GROUP_WHO)) {
108 aceprop.flags = SMB_ACE4_ID_SPECIAL;
109 aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
110 } else if (!strcmp(nfs4acl->ace[i].e_who,
111 NFS4ACL_XATTR_EVERYONE_WHO)) {
112 aceprop.flags = SMB_ACE4_ID_SPECIAL;
113 aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
117 if(smb_add_ace4(pacl, &aceprop) == NULL) {
119 return NT_STATUS_NO_MEMORY;
128 /* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
129 static NTSTATUS nfs4_fget_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
130 files_struct *fsp, struct SMB4ACL_T **ppacl)
133 DATA_BLOB blob = data_blob_null;
135 TALLOC_CTX *frame = talloc_stackframe();
139 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
143 return NT_STATUS_NO_MEMORY;
145 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, NFS4ACL_NDR_XATTR_NAME, blob.data, blob.length);
146 blob.length = length;
147 } while (length == -1 && errno == ERANGE);
150 return map_nt_error_from_unix(errno);
152 status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl);
157 /* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
158 static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle,
160 const struct smb_filename *smb_fname,
161 struct SMB4ACL_T **ppacl)
164 DATA_BLOB blob = data_blob_null;
166 TALLOC_CTX *frame = talloc_stackframe();
170 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
174 return NT_STATUS_NO_MEMORY;
176 length = SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
177 NFS4ACL_NDR_XATTR_NAME, blob.data, blob.length);
178 blob.length = length;
179 } while (length == -1 && errno == ERANGE);
182 return map_nt_error_from_unix(errno);
184 status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl);
189 static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
190 struct SMB4ACL_T *smbacl,
191 struct nfs4acl **pnfs4acl,
192 bool denymissingspecial)
194 struct nfs4acl *nfs4acl;
195 struct SMB4ACE_T *smbace;
196 bool have_special_id = false;
199 /* allocate the field of NFS4 aces */
200 nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
201 if(nfs4acl == NULL) {
206 nfs4acl->a_count = smb_get_naces(smbacl);
208 nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
210 if(nfs4acl->ace == NULL) {
211 TALLOC_FREE(nfs4acl);
216 /* handle all aces */
217 for(smbace = smb_first_ace4(smbacl), i = 0;
219 smbace = smb_next_ace4(smbace), i++) {
220 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
222 nfs4acl->ace[i].e_type = aceprop->aceType;
223 nfs4acl->ace[i].e_flags = aceprop->aceFlags;
224 nfs4acl->ace[i].e_mask = aceprop->aceMask;
225 nfs4acl->ace[i].e_id = aceprop->who.id;
226 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
227 switch(aceprop->who.special_id) {
228 case SMB_ACE4_WHO_EVERYONE:
229 nfs4acl->ace[i].e_who =
230 NFS4ACL_XATTR_EVERYONE_WHO;
232 case SMB_ACE4_WHO_OWNER:
233 nfs4acl->ace[i].e_who =
234 NFS4ACL_XATTR_OWNER_WHO;
236 case SMB_ACE4_WHO_GROUP:
237 nfs4acl->ace[i].e_who =
238 NFS4ACL_XATTR_GROUP_WHO;
241 DEBUG(8, ("unsupported special_id %d\n", \
242 aceprop->who.special_id));
243 continue; /* don't add it !!! */
245 have_special_id = true;
247 nfs4acl->ace[i].e_who = "";
251 if (!have_special_id && denymissingspecial) {
252 TALLOC_FREE(nfs4acl);
257 SMB_ASSERT(i == nfs4acl->a_count);
263 /* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
264 static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
266 struct SMB4ACL_T *smbacl)
268 TALLOC_CTX *frame = talloc_stackframe();
269 struct nfs4acl *nfs4acl;
271 bool denymissingspecial;
274 denymissingspecial = lp_parm_bool(fsp->conn->params->service,
276 "denymissingspecial", false);
278 if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
279 denymissingspecial)) {
280 DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
285 blob = nfs4acl_acl2blob(frame, nfs4acl);
287 DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
292 if (fsp->fh->fd == -1) {
293 DEBUG(0, ("Error: fsp->fh->fd == -1\n"));
295 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_NDR_XATTR_NAME,
296 blob.data, blob.length, 0);
298 DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
304 static NTSTATUS nfs4acl_xattr_default_sd(
305 struct vfs_handle_struct *handle,
306 const struct smb_filename *smb_fname,
308 struct security_descriptor **sd)
310 struct nfs4acl_config *config = NULL;
311 enum default_acl_style default_acl_style;
312 mode_t required_mode;
313 SMB_STRUCT_STAT sbuf = smb_fname->st;
316 SMB_VFS_HANDLE_GET_DATA(handle, config,
317 struct nfs4acl_config,
318 return NT_STATUS_INTERNAL_ERROR);
320 default_acl_style = config->default_acl_style;
322 if (!VALID_STAT(sbuf)) {
323 ret = vfs_stat_smb_basename(handle->conn,
327 return map_nt_error_from_unix(errno);
331 if (S_ISDIR(sbuf.st_ex_mode)) {
332 required_mode = 0777;
334 required_mode = 0666;
336 if ((sbuf.st_ex_mode & required_mode) != required_mode) {
337 default_acl_style = DEFAULT_ACL_POSIX;
340 return make_default_filesystem_acl(mem_ctx,
342 smb_fname->base_name,
347 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
348 struct files_struct *fsp,
349 uint32_t security_info,
351 struct security_descriptor **ppdesc)
353 struct SMB4ACL_T *pacl;
355 TALLOC_CTX *frame = talloc_stackframe();
357 status = nfs4_fget_nfs4_acl(handle, frame, fsp, &pacl);
358 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
360 return nfs4acl_xattr_default_sd(
361 handle, fsp->fsp_name, mem_ctx, ppdesc);
363 if (!NT_STATUS_IS_OK(status)) {
368 status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
374 static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
375 const struct smb_filename *smb_fname,
376 uint32_t security_info,
378 struct security_descriptor **ppdesc)
380 struct SMB4ACL_T *pacl;
382 TALLOC_CTX *frame = talloc_stackframe();
384 status = nfs4_get_nfs4_acl(handle, frame, smb_fname, &pacl);
385 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
387 return nfs4acl_xattr_default_sd(
388 handle, smb_fname, mem_ctx, ppdesc);
390 if (!NT_STATUS_IS_OK(status)) {
395 status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
396 security_info, mem_ctx, ppdesc,
402 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
404 uint32_t security_info_sent,
405 const struct security_descriptor *psd)
407 return smb_set_nt_acl_nfs4(handle, fsp, NULL, security_info_sent,
408 psd, nfs4acl_xattr_fset_smb4acl);
411 static int nfs4acl_connect(struct vfs_handle_struct *handle,
415 struct nfs4acl_config *config = NULL;
416 const struct enum_list *default_acl_style_list = NULL;
417 const char *default_xattr_name = NULL;
419 unsigned nfs_version;
422 default_acl_style_list = get_default_acl_style_list();
424 config = talloc_zero(handle->conn, struct nfs4acl_config);
425 if (config == NULL) {
426 DBG_ERR("talloc_zero() failed\n");
430 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
436 ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
442 enumval = lp_parm_enum(SNUM(handle->conn),
446 NFS4ACL_ENCODING_NDR);
448 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
451 config->encoding = (enum nfs4acl_encoding)enumval;
453 switch (config->encoding) {
454 case NFS4ACL_ENCODING_NDR:
456 default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
460 nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
464 switch (nfs_version) {
466 config->nfs_version = ACL4_XATTR_VERSION_40;
469 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
473 config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
476 default_acl_style_list,
477 DEFAULT_ACL_EVERYONE);
479 config->xattr_name = lp_parm_talloc_string(config,
485 SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
489 * Ensure we have the parameters correct if we're using this module.
491 DBG_NOTICE("Setting 'inherit acls = true', "
492 "'dos filemode = true', "
493 "'force unknown acl user = true', "
494 "'create mask = 0666', "
495 "'directory mask = 0777' and "
496 "'store dos attributes = yes' "
497 "for service [%s]\n", service);
499 lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
500 lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
501 lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
502 lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
503 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
504 lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
510 As long as Samba does not support an exiplicit method for a module
511 to define conflicting vfs methods, we should override all conflicting
512 methods here. That way, we know we are using the NFSv4 storage
514 Function declarations taken from vfs_solarisacl
517 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
518 const struct smb_filename *smb_fname,
522 return (SMB_ACL_T)NULL;
525 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
529 return (SMB_ACL_T)NULL;
532 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
533 const struct smb_filename *smb_fname,
540 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
547 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
548 const struct smb_filename *smb_fname)
553 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
554 const struct smb_filename *smb_fname,
556 char **blob_description,
562 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)
567 /* VFS operations structure */
569 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
570 .connect_fn = nfs4acl_connect,
571 .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
572 .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
573 .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
575 .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
576 .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
577 .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
578 .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
579 .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
580 .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
581 .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
584 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *);
585 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
587 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",