vfs_io_uring: move error handling out of vfs_io_uring_pread_recv()
[Samba.git] / source3 / modules / vfs_nfs4acl_xattr.c
blobf8cbe7964d14b0d396122f8aa17f9d9e2a7edad6
1 /*
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/>.
29 #include "includes.h"
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"
41 #undef DBGC_CLASS
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;
58 mode_t expected_mode;
59 int ret;
61 SMB_VFS_HANDLE_GET_DATA(handle, config,
62 struct nfs4acl_config,
63 return false);
65 if (!config->validate_mode) {
66 return true;
69 if (!VALID_STAT(smb_fname->st)) {
70 /* might be a create */
71 return true;
74 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
75 expected_mode = 0777;
76 } else {
77 expected_mode = 0666;
79 if ((smb_fname->st.st_ex_mode & expected_mode) == expected_mode) {
80 return true;
83 ret = SMB_VFS_NEXT_REMOVEXATTR(handle,
84 smb_fname,
85 config->xattr_name);
86 if (ret != 0 && errno != ENOATTR) {
87 DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno));
88 return false;
91 return true;
94 static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
95 files_struct *fsp,
96 const struct smb_filename *smb_fname_in,
97 TALLOC_CTX *mem_ctx,
98 DATA_BLOB *blob)
100 struct nfs4acl_config *config = NULL;
101 const struct smb_filename *smb_fname = NULL;
102 size_t allocsize = 256;
103 ssize_t length;
104 bool ok;
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);
124 if (!ok) {
125 return NT_STATUS_INTERNAL_ERROR;
128 do {
130 allocsize *= 4;
131 ok = data_blob_realloc(mem_ctx, blob, allocsize);
132 if (!ok) {
133 return NT_STATUS_NO_MEMORY;
136 if (fsp != NULL && fsp->fh->fd != -1) {
137 length = SMB_VFS_NEXT_FGETXATTR(handle,
138 fsp,
139 config->xattr_name,
140 blob->data,
141 blob->length);
142 } else {
143 length = SMB_VFS_NEXT_GETXATTR(handle,
144 smb_fname,
145 config->xattr_name,
146 blob->data,
147 blob->length);
149 } while (length == -1 && errno == ERANGE && allocsize <= 65536);
151 if (length == -1) {
152 return map_nt_error_from_unix(errno);
155 return NT_STATUS_OK;
158 static NTSTATUS nfs4acl_xattr_default_sd(
159 struct vfs_handle_struct *handle,
160 const struct smb_filename *smb_fname,
161 TALLOC_CTX *mem_ctx,
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;
168 int ret;
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,
178 smb_fname,
179 &sbuf);
180 if (ret != 0) {
181 return map_nt_error_from_unix(errno);
185 if (S_ISDIR(sbuf.st_ex_mode)) {
186 required_mode = 0777;
187 } else {
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,
195 default_acl_style,
196 smb_fname->base_name,
197 &sbuf,
198 sd);
201 static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
202 DATA_BLOB *blob,
203 TALLOC_CTX *mem_ctx,
204 struct SMB4ACL_T **smb4acl)
206 struct nfs4acl_config *config = NULL;
207 NTSTATUS status;
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);
216 break;
217 case NFS4ACL_ENCODING_XDR:
218 status = nfs4acl_xdr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
219 break;
220 case NFS4ACL_ENCODING_NFS:
221 status = nfs4acl_nfs_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
222 break;
223 default:
224 status = NT_STATUS_INTERNAL_ERROR;
225 break;
228 return status;
231 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
232 struct files_struct *fsp,
233 uint32_t security_info,
234 TALLOC_CTX *mem_ctx,
235 struct security_descriptor **sd)
237 struct SMB4ACL_T *smb4acl = NULL;
238 TALLOC_CTX *frame = talloc_stackframe();
239 DATA_BLOB blob;
240 NTSTATUS status;
242 status = nfs4acl_get_blob(handle, fsp, NULL, frame, &blob);
243 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
244 TALLOC_FREE(frame);
245 return nfs4acl_xattr_default_sd(
246 handle, fsp->fsp_name, mem_ctx, sd);
248 if (!NT_STATUS_IS_OK(status)) {
249 TALLOC_FREE(frame);
250 return status;
253 status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
254 if (!NT_STATUS_IS_OK(status)) {
255 TALLOC_FREE(frame);
256 return status;
259 status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
260 sd, smb4acl);
261 TALLOC_FREE(frame);
262 return status;
265 static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
266 const struct smb_filename *smb_fname,
267 uint32_t security_info,
268 TALLOC_CTX *mem_ctx,
269 struct security_descriptor **sd)
271 struct SMB4ACL_T *smb4acl = NULL;
272 TALLOC_CTX *frame = talloc_stackframe();
273 DATA_BLOB blob;
274 NTSTATUS status;
276 status = nfs4acl_get_blob(handle, NULL, smb_fname, frame, &blob);
277 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
278 TALLOC_FREE(frame);
279 return nfs4acl_xattr_default_sd(
280 handle, smb_fname, mem_ctx, sd);
282 if (!NT_STATUS_IS_OK(status)) {
283 TALLOC_FREE(frame);
284 return status;
287 status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
288 if (!NT_STATUS_IS_OK(status)) {
289 TALLOC_FREE(frame);
290 return status;
293 status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
294 security_info, mem_ctx, sd,
295 smb4acl);
296 TALLOC_FREE(frame);
297 return status;
300 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
301 files_struct *fsp,
302 struct SMB4ACL_T *smb4acl)
304 struct nfs4acl_config *config = NULL;
305 DATA_BLOB blob;
306 NTSTATUS status;
307 int saved_errno = 0;
308 int ret;
310 SMB_VFS_HANDLE_GET_DATA(handle, config,
311 struct nfs4acl_config,
312 return false);
314 switch (config->encoding) {
315 case NFS4ACL_ENCODING_NDR:
316 status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
317 smb4acl, &blob);
318 break;
319 case NFS4ACL_ENCODING_XDR:
320 status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
321 smb4acl, &blob);
322 break;
323 case NFS4ACL_ENCODING_NFS:
324 status = nfs4acl_smb4acl_to_nfs_blob(handle, talloc_tos(),
325 smb4acl, &blob);
326 break;
327 default:
328 status = NT_STATUS_INTERNAL_ERROR;
329 break;
331 if (!NT_STATUS_IS_OK(status)) {
332 return false;
335 if (fsp->fh->fd != -1) {
336 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
337 blob.data, blob.length, 0);
338 } else {
339 ret = SMB_VFS_NEXT_SETXATTR(handle, fsp->fsp_name,
340 config->xattr_name,
341 blob.data, blob.length, 0);
343 if (ret != 0) {
344 saved_errno = errno;
346 data_blob_free(&blob);
347 if (saved_errno != 0) {
348 errno = saved_errno;
350 if (ret != 0) {
351 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
352 return false;
355 return true;
358 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
359 files_struct *fsp,
360 uint32_t security_info_sent,
361 const struct security_descriptor *psd)
363 struct nfs4acl_config *config = NULL;
364 const struct security_token *token = NULL;
365 mode_t existing_mode;
366 mode_t expected_mode;
367 mode_t restored_mode;
368 bool chown_needed = false;
369 struct dom_sid_buf buf;
370 NTSTATUS status;
371 int ret;
373 SMB_VFS_HANDLE_GET_DATA(handle, config,
374 struct nfs4acl_config,
375 return NT_STATUS_INTERNAL_ERROR);
377 if (!VALID_STAT(fsp->fsp_name->st)) {
378 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
379 return NT_STATUS_INTERNAL_ERROR;
382 existing_mode = fsp->fsp_name->st.st_ex_mode;
383 if (S_ISDIR(existing_mode)) {
384 expected_mode = 0777;
385 } else {
386 expected_mode = 0666;
388 if (!config->validate_mode) {
389 existing_mode = 0;
390 expected_mode = 0;
392 if ((existing_mode & expected_mode) != expected_mode) {
394 restored_mode = existing_mode | expected_mode;
396 if (fsp->fh->fd != -1) {
397 ret = SMB_VFS_NEXT_FCHMOD(handle,
398 fsp,
399 restored_mode);
400 } else {
401 ret = SMB_VFS_NEXT_CHMOD(handle,
402 fsp->fsp_name,
403 restored_mode);
405 if (ret != 0) {
406 DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
407 fsp_str_dbg(fsp), existing_mode,
408 strerror(errno));
409 return map_nt_error_from_unix(errno);
413 status = smb_set_nt_acl_nfs4(handle,
414 fsp,
415 &config->nfs4_params,
416 security_info_sent,
417 psd,
418 nfs4acl_smb4acl_set_fn);
419 if (NT_STATUS_IS_OK(status)) {
420 return NT_STATUS_OK;
422 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
423 return status;
427 * We got access denied. If we're already root, or we didn't
428 * need to do a chown, or the fsp isn't open with WRITE_OWNER
429 * access, just return.
432 if ((security_info_sent & SECINFO_OWNER) &&
433 (psd->owner_sid != NULL))
435 chown_needed = true;
437 if ((security_info_sent & SECINFO_GROUP) &&
438 (psd->group_sid != NULL))
440 chown_needed = true;
443 if (get_current_uid(handle->conn) == 0 ||
444 chown_needed == false ||
445 !(fsp->access_mask & SEC_STD_WRITE_OWNER))
447 return NT_STATUS_ACCESS_DENIED;
451 * Only allow take-ownership, not give-ownership. That's the way Windows
452 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
453 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
454 * objectstore, as determined in an implementation specific manner, the
455 * object store MUST return STATUS_INVALID_OWNER.
457 token = get_current_nttok(fsp->conn);
458 if (!security_token_is_sid(token, psd->owner_sid)) {
459 return NT_STATUS_INVALID_OWNER;
462 DBG_DEBUG("overriding chown on file %s for sid %s\n",
463 fsp_str_dbg(fsp),
464 dom_sid_str_buf(psd->owner_sid, &buf));
466 status = smb_set_nt_acl_nfs4(handle,
467 fsp,
468 &config->nfs4_params,
469 security_info_sent,
470 psd,
471 nfs4acl_smb4acl_set_fn);
472 return status;
475 static int nfs4acl_connect(struct vfs_handle_struct *handle,
476 const char *service,
477 const char *user)
479 const struct loadparm_substitution *lp_sub =
480 loadparm_s3_global_substitution();
481 struct nfs4acl_config *config = NULL;
482 const struct enum_list *default_acl_style_list = NULL;
483 const char *default_xattr_name = NULL;
484 bool default_validate_mode = true;
485 int enumval;
486 unsigned nfs_version;
487 int ret;
489 default_acl_style_list = get_default_acl_style_list();
491 config = talloc_zero(handle->conn, struct nfs4acl_config);
492 if (config == NULL) {
493 DBG_ERR("talloc_zero() failed\n");
494 return -1;
497 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
498 if (ret < 0) {
499 TALLOC_FREE(config);
500 return ret;
503 ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
504 if (ret < 0) {
505 TALLOC_FREE(config);
506 return ret;
509 enumval = lp_parm_enum(SNUM(handle->conn),
510 "nfs4acl_xattr",
511 "encoding",
512 nfs4acl_encoding,
513 NFS4ACL_ENCODING_NDR);
514 if (enumval == -1) {
515 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
516 return -1;
518 config->encoding = (enum nfs4acl_encoding)enumval;
520 switch (config->encoding) {
521 case NFS4ACL_ENCODING_XDR:
522 default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
523 break;
524 case NFS4ACL_ENCODING_NFS:
525 default_xattr_name = NFS4ACL_NFS_XATTR_NAME;
526 default_validate_mode = false;
527 break;
528 case NFS4ACL_ENCODING_NDR:
529 default:
530 default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
531 break;
534 nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
535 "nfs4acl_xattr",
536 "version",
537 41);
538 switch (nfs_version) {
539 case 40:
540 config->nfs_version = ACL4_XATTR_VERSION_40;
541 break;
542 case 41:
543 config->nfs_version = ACL4_XATTR_VERSION_41;
544 break;
545 default:
546 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
547 break;
550 config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
551 "nfs4acl_xattr",
552 "default acl style",
553 default_acl_style_list,
554 DEFAULT_ACL_EVERYONE);
556 config->xattr_name = lp_parm_substituted_string(config, lp_sub,
557 SNUM(handle->conn),
558 "nfs4acl_xattr",
559 "xattr_name",
560 default_xattr_name);
562 config->nfs4_id_numeric = lp_parm_bool(SNUM(handle->conn),
563 "nfs4acl_xattr",
564 "nfs4_id_numeric",
565 false);
568 config->validate_mode = lp_parm_bool(SNUM(handle->conn),
569 "nfs4acl_xattr",
570 "validate_mode",
571 default_validate_mode);
573 SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
574 return -1);
577 * Ensure we have the parameters correct if we're using this module.
579 DBG_NOTICE("Setting 'inherit acls = true', "
580 "'dos filemode = true', "
581 "'force unknown acl user = true', "
582 "'create mask = 0666', "
583 "'directory mask = 0777' and "
584 "'store dos attributes = yes' "
585 "for service [%s]\n", service);
587 lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
588 lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
589 lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
590 lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
591 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
592 lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
594 return 0;
598 As long as Samba does not support an exiplicit method for a module
599 to define conflicting vfs methods, we should override all conflicting
600 methods here. That way, we know we are using the NFSv4 storage
602 Function declarations taken from vfs_solarisacl
605 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
606 const struct smb_filename *smb_fname,
607 SMB_ACL_TYPE_T type,
608 TALLOC_CTX *mem_ctx)
610 return (SMB_ACL_T)NULL;
613 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
614 files_struct *fsp,
615 TALLOC_CTX *mem_ctx)
617 return (SMB_ACL_T)NULL;
620 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
621 const struct smb_filename *smb_fname,
622 SMB_ACL_TYPE_T type,
623 SMB_ACL_T theacl)
625 return -1;
628 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
629 files_struct *fsp,
630 SMB_ACL_T theacl)
632 return -1;
635 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
636 const struct smb_filename *smb_fname)
638 return -1;
641 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
642 const struct smb_filename *smb_fname,
643 TALLOC_CTX *mem_ctx,
644 char **blob_description,
645 DATA_BLOB *blob)
647 return -1;
650 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 return -1;
655 /* VFS operations structure */
657 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
658 .connect_fn = nfs4acl_connect,
659 .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
660 .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
661 .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
663 .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
664 .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
665 .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
666 .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
667 .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
668 .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
669 .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
672 static_decl_vfs;
673 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
675 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
676 &nfs4acl_xattr_fns);