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 NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
46 const struct smb_filename *smb_fname_in,
50 struct nfs4acl_config *config = NULL;
51 const struct smb_filename *smb_fname = NULL;
52 size_t allocsize = 256;
56 SMB_VFS_HANDLE_GET_DATA(handle, config,
57 struct nfs4acl_config,
58 return NT_STATUS_INTERNAL_ERROR);
60 *blob = data_blob_null;
62 if (fsp == NULL && smb_fname_in == NULL) {
63 return NT_STATUS_INTERNAL_ERROR;
65 smb_fname = smb_fname_in;
66 if (smb_fname == NULL) {
67 smb_fname = fsp->fsp_name;
69 if (smb_fname == NULL) {
70 return NT_STATUS_INTERNAL_ERROR;
75 ok = data_blob_realloc(mem_ctx, blob, allocsize);
77 return NT_STATUS_NO_MEMORY;
80 if (fsp != NULL && fsp->fh->fd != -1) {
81 length = SMB_VFS_NEXT_FGETXATTR(handle,
87 length = SMB_VFS_NEXT_GETXATTR(handle,
93 } while (length == -1 && errno == ERANGE && allocsize <= 65536);
96 return map_nt_error_from_unix(errno);
102 static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
104 enum ndr_err_code ndr_err;
105 struct nfs4acl *acl = talloc_zero(mem_ctx, struct nfs4acl);
112 ndr_err = ndr_pull_struct_blob(blob, acl, acl,
113 (ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
115 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
116 DBG_ERR("ndr_pull_acl_t failed: %s\n", ndr_errstr(ndr_err));
123 static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
125 enum ndr_err_code ndr_err;
128 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
129 (ndr_push_flags_fn_t)ndr_push_nfs4acl);
131 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
132 DBG_ERR("ndr_push_acl_t failed: %s\n", ndr_errstr(ndr_err));
133 return data_blob_null;
138 static NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
141 struct SMB4ACL_T **_smb4acl)
143 struct nfs4acl *nfs4acl = NULL;
144 struct SMB4ACL_T *smb4acl = NULL;
145 TALLOC_CTX *frame = talloc_stackframe();
146 struct nfs4acl_config *config = NULL;
149 SMB_VFS_HANDLE_GET_DATA(handle, config,
150 struct nfs4acl_config,
151 return NT_STATUS_INTERNAL_ERROR);
153 nfs4acl = nfs4acl_blob2acl(blob, frame);
154 if (nfs4acl == NULL) {
156 return NT_STATUS_INTERNAL_ERROR;
159 smb4acl = smb_create_smb4acl(mem_ctx);
160 if (smb4acl == NULL) {
162 return NT_STATUS_NO_MEMORY;
165 for (i = 0; i < nfs4acl->a_count; i++) {
166 SMB_ACE4PROP_T aceprop;
168 aceprop.aceType = (uint32_t) nfs4acl->ace[i].e_type;
169 aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
170 aceprop.aceMask = (uint32_t) nfs4acl->ace[i].e_mask;
171 aceprop.who.id = (uint32_t) nfs4acl->ace[i].e_id;
173 if (!strcmp(nfs4acl->ace[i].e_who,
174 NFS4ACL_XATTR_OWNER_WHO)) {
175 aceprop.flags = SMB_ACE4_ID_SPECIAL;
176 aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
177 } else if (!strcmp(nfs4acl->ace[i].e_who,
178 NFS4ACL_XATTR_GROUP_WHO)) {
179 aceprop.flags = SMB_ACE4_ID_SPECIAL;
180 aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
181 } else if (!strcmp(nfs4acl->ace[i].e_who,
182 NFS4ACL_XATTR_EVERYONE_WHO)) {
183 aceprop.flags = SMB_ACE4_ID_SPECIAL;
184 aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
188 if (smb_add_ace4(smb4acl, &aceprop) == NULL) {
190 return NT_STATUS_NO_MEMORY;
199 static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
200 struct SMB4ACL_T *smbacl,
201 struct nfs4acl **_nfs4acl,
202 bool denymissingspecial)
204 struct nfs4acl *nfs4acl = NULL;
205 struct SMB4ACE_T *smbace = NULL;
206 bool have_special_id = false;
209 nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
210 if (nfs4acl == NULL) {
215 nfs4acl->a_count = smb_get_naces(smbacl);
217 nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
219 if (nfs4acl->ace == NULL) {
220 TALLOC_FREE(nfs4acl);
225 for (smbace = smb_first_ace4(smbacl), i = 0;
227 smbace = smb_next_ace4(smbace), i++)
229 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
231 nfs4acl->ace[i].e_type = aceprop->aceType;
232 nfs4acl->ace[i].e_flags = aceprop->aceFlags;
233 nfs4acl->ace[i].e_mask = aceprop->aceMask;
234 nfs4acl->ace[i].e_id = aceprop->who.id;
235 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
236 switch(aceprop->who.special_id) {
237 case SMB_ACE4_WHO_EVERYONE:
238 nfs4acl->ace[i].e_who =
239 NFS4ACL_XATTR_EVERYONE_WHO;
241 case SMB_ACE4_WHO_OWNER:
242 nfs4acl->ace[i].e_who =
243 NFS4ACL_XATTR_OWNER_WHO;
245 case SMB_ACE4_WHO_GROUP:
246 nfs4acl->ace[i].e_who =
247 NFS4ACL_XATTR_GROUP_WHO;
250 DBG_DEBUG("unsupported special_id %d\n",
251 aceprop->who.special_id);
252 continue; /* don't add it !!! */
254 have_special_id = true;
256 nfs4acl->ace[i].e_who = "";
260 if (!have_special_id && denymissingspecial) {
261 TALLOC_FREE(nfs4acl);
266 SMB_ASSERT(i == nfs4acl->a_count);
272 static NTSTATUS nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct *handle,
274 struct SMB4ACL_T *smb4acl,
277 struct nfs4acl *nfs4acl = NULL;
279 bool denymissingspecial;
282 denymissingspecial = lp_parm_bool(SNUM(handle->conn),
284 "denymissingspecial", false);
286 ok = nfs4acl_smb4acl2nfs4acl(talloc_tos(), smb4acl, &nfs4acl,
289 DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
290 return NT_STATUS_INTERNAL_ERROR;
293 blob = nfs4acl_acl2blob(mem_ctx, nfs4acl);
294 TALLOC_FREE(nfs4acl);
295 if (blob.data == NULL) {
296 DBG_ERR("Failed to convert ACL to linear blob for xattr\n");
297 return NT_STATUS_INTERNAL_ERROR;
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_blob_to_smb4(struct vfs_handle_struct *handle,
350 struct SMB4ACL_T **smb4acl)
352 struct nfs4acl_config *config = NULL;
355 SMB_VFS_HANDLE_GET_DATA(handle, config,
356 struct nfs4acl_config,
357 return NT_STATUS_INTERNAL_ERROR);
359 switch (config->encoding) {
360 case NFS4ACL_ENCODING_NDR:
361 status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
364 status = NT_STATUS_INTERNAL_ERROR;
371 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
372 struct files_struct *fsp,
373 uint32_t security_info,
375 struct security_descriptor **sd)
377 struct SMB4ACL_T *smb4acl = NULL;
378 TALLOC_CTX *frame = talloc_stackframe();
382 status = nfs4acl_get_blob(handle, fsp, NULL, frame, &blob);
383 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
385 return nfs4acl_xattr_default_sd(
386 handle, fsp->fsp_name, mem_ctx, sd);
388 if (!NT_STATUS_IS_OK(status)) {
393 status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
394 if (!NT_STATUS_IS_OK(status)) {
399 status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
405 static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
406 const struct smb_filename *smb_fname,
407 uint32_t security_info,
409 struct security_descriptor **sd)
411 struct SMB4ACL_T *smb4acl = NULL;
412 TALLOC_CTX *frame = talloc_stackframe();
416 status = nfs4acl_get_blob(handle, NULL, smb_fname, frame, &blob);
417 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
419 return nfs4acl_xattr_default_sd(
420 handle, smb_fname, mem_ctx, sd);
422 if (!NT_STATUS_IS_OK(status)) {
427 status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
428 if (!NT_STATUS_IS_OK(status)) {
433 status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
434 security_info, mem_ctx, sd,
440 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
442 struct SMB4ACL_T *smb4acl)
444 struct nfs4acl_config *config = NULL;
449 SMB_VFS_HANDLE_GET_DATA(handle, config,
450 struct nfs4acl_config,
453 switch (config->encoding) {
454 case NFS4ACL_ENCODING_NDR:
455 status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
459 status = NT_STATUS_INTERNAL_ERROR;
462 if (!NT_STATUS_IS_OK(status)) {
466 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
467 blob.data, blob.length, 0);
468 data_blob_free(&blob);
470 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
477 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
479 uint32_t security_info_sent,
480 const struct security_descriptor *psd)
482 struct nfs4acl_config *config = NULL;
484 SMB_VFS_HANDLE_GET_DATA(handle, config,
485 struct nfs4acl_config,
486 return NT_STATUS_INTERNAL_ERROR);
488 return smb_set_nt_acl_nfs4(handle,
490 &config->nfs4_params,
493 nfs4acl_smb4acl_set_fn);
496 static int nfs4acl_connect(struct vfs_handle_struct *handle,
500 struct nfs4acl_config *config = NULL;
501 const struct enum_list *default_acl_style_list = NULL;
502 const char *default_xattr_name = NULL;
504 unsigned nfs_version;
507 default_acl_style_list = get_default_acl_style_list();
509 config = talloc_zero(handle->conn, struct nfs4acl_config);
510 if (config == NULL) {
511 DBG_ERR("talloc_zero() failed\n");
515 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
521 ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
527 enumval = lp_parm_enum(SNUM(handle->conn),
531 NFS4ACL_ENCODING_NDR);
533 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
536 config->encoding = (enum nfs4acl_encoding)enumval;
538 switch (config->encoding) {
539 case NFS4ACL_ENCODING_NDR:
541 default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
545 nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
549 switch (nfs_version) {
551 config->nfs_version = ACL4_XATTR_VERSION_40;
554 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
558 config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
561 default_acl_style_list,
562 DEFAULT_ACL_EVERYONE);
564 config->xattr_name = lp_parm_talloc_string(config,
570 SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
574 * Ensure we have the parameters correct if we're using this module.
576 DBG_NOTICE("Setting 'inherit acls = true', "
577 "'dos filemode = true', "
578 "'force unknown acl user = true', "
579 "'create mask = 0666', "
580 "'directory mask = 0777' and "
581 "'store dos attributes = yes' "
582 "for service [%s]\n", service);
584 lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
585 lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
586 lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
587 lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
588 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
589 lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
595 As long as Samba does not support an exiplicit method for a module
596 to define conflicting vfs methods, we should override all conflicting
597 methods here. That way, we know we are using the NFSv4 storage
599 Function declarations taken from vfs_solarisacl
602 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
603 const struct smb_filename *smb_fname,
607 return (SMB_ACL_T)NULL;
610 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
614 return (SMB_ACL_T)NULL;
617 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
618 const struct smb_filename *smb_fname,
625 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
632 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
633 const struct smb_filename *smb_fname)
638 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
639 const struct smb_filename *smb_fname,
641 char **blob_description,
647 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)
652 /* VFS operations structure */
654 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
655 .connect_fn = nfs4acl_connect,
656 .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
657 .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
658 .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
660 .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
661 .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
662 .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
663 .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
664 .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
665 .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
666 .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
669 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *);
670 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
672 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",