s3:lib: Make sure that have_rsrc is initialized
[Samba.git] / source3 / modules / vfs_nfs4acl_xattr.c
blobb1b1eae49f8d8f1b5561a6a0582c4aac4124eb55
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_at(struct vfs_handle_struct *handle,
266 struct files_struct *dirfsp,
267 const struct smb_filename *smb_fname,
268 uint32_t security_info,
269 TALLOC_CTX *mem_ctx,
270 struct security_descriptor **sd)
272 struct SMB4ACL_T *smb4acl = NULL;
273 TALLOC_CTX *frame = talloc_stackframe();
274 DATA_BLOB blob;
275 NTSTATUS status;
277 SMB_ASSERT(dirfsp == handle->conn->cwd_fsp);
279 status = nfs4acl_get_blob(handle, NULL, smb_fname, frame, &blob);
280 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
281 TALLOC_FREE(frame);
282 return nfs4acl_xattr_default_sd(
283 handle, smb_fname, mem_ctx, sd);
285 if (!NT_STATUS_IS_OK(status)) {
286 TALLOC_FREE(frame);
287 return status;
290 status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
291 if (!NT_STATUS_IS_OK(status)) {
292 TALLOC_FREE(frame);
293 return status;
296 status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
297 security_info, mem_ctx, sd,
298 smb4acl);
299 TALLOC_FREE(frame);
300 return status;
303 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
304 files_struct *fsp,
305 struct SMB4ACL_T *smb4acl)
307 struct nfs4acl_config *config = NULL;
308 DATA_BLOB blob;
309 NTSTATUS status;
310 int saved_errno = 0;
311 int ret;
313 SMB_VFS_HANDLE_GET_DATA(handle, config,
314 struct nfs4acl_config,
315 return false);
317 switch (config->encoding) {
318 case NFS4ACL_ENCODING_NDR:
319 status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
320 smb4acl, &blob);
321 break;
322 case NFS4ACL_ENCODING_XDR:
323 status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
324 smb4acl, &blob);
325 break;
326 case NFS4ACL_ENCODING_NFS:
327 status = nfs4acl_smb4acl_to_nfs_blob(handle, talloc_tos(),
328 smb4acl, &blob);
329 break;
330 default:
331 status = NT_STATUS_INTERNAL_ERROR;
332 break;
334 if (!NT_STATUS_IS_OK(status)) {
335 return false;
338 if (fsp->fh->fd != -1) {
339 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
340 blob.data, blob.length, 0);
341 } else {
342 ret = SMB_VFS_NEXT_SETXATTR(handle, fsp->fsp_name,
343 config->xattr_name,
344 blob.data, blob.length, 0);
346 if (ret != 0) {
347 saved_errno = errno;
349 data_blob_free(&blob);
350 if (saved_errno != 0) {
351 errno = saved_errno;
353 if (ret != 0) {
354 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
355 return false;
358 return true;
361 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
362 files_struct *fsp,
363 uint32_t security_info_sent,
364 const struct security_descriptor *psd)
366 struct nfs4acl_config *config = NULL;
367 const struct security_token *token = NULL;
368 mode_t existing_mode;
369 mode_t expected_mode;
370 mode_t restored_mode;
371 bool chown_needed = false;
372 struct dom_sid_buf buf;
373 NTSTATUS status;
374 int ret;
376 SMB_VFS_HANDLE_GET_DATA(handle, config,
377 struct nfs4acl_config,
378 return NT_STATUS_INTERNAL_ERROR);
380 if (!VALID_STAT(fsp->fsp_name->st)) {
381 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
382 return NT_STATUS_INTERNAL_ERROR;
385 existing_mode = fsp->fsp_name->st.st_ex_mode;
386 if (S_ISDIR(existing_mode)) {
387 expected_mode = 0777;
388 } else {
389 expected_mode = 0666;
391 if (!config->validate_mode) {
392 existing_mode = 0;
393 expected_mode = 0;
395 if ((existing_mode & expected_mode) != expected_mode) {
397 restored_mode = existing_mode | expected_mode;
399 if (fsp->fh->fd != -1) {
400 ret = SMB_VFS_NEXT_FCHMOD(handle,
401 fsp,
402 restored_mode);
403 } else {
404 ret = SMB_VFS_NEXT_CHMOD(handle,
405 fsp->fsp_name,
406 restored_mode);
408 if (ret != 0) {
409 DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
410 fsp_str_dbg(fsp), existing_mode,
411 strerror(errno));
412 return map_nt_error_from_unix(errno);
416 status = smb_set_nt_acl_nfs4(handle,
417 fsp,
418 &config->nfs4_params,
419 security_info_sent,
420 psd,
421 nfs4acl_smb4acl_set_fn);
422 if (NT_STATUS_IS_OK(status)) {
423 return NT_STATUS_OK;
425 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
426 return status;
430 * We got access denied. If we're already root, or we didn't
431 * need to do a chown, or the fsp isn't open with WRITE_OWNER
432 * access, just return.
435 if ((security_info_sent & SECINFO_OWNER) &&
436 (psd->owner_sid != NULL))
438 chown_needed = true;
440 if ((security_info_sent & SECINFO_GROUP) &&
441 (psd->group_sid != NULL))
443 chown_needed = true;
446 if (get_current_uid(handle->conn) == 0 ||
447 chown_needed == false ||
448 !(fsp->access_mask & SEC_STD_WRITE_OWNER))
450 return NT_STATUS_ACCESS_DENIED;
454 * Only allow take-ownership, not give-ownership. That's the way Windows
455 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
456 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
457 * objectstore, as determined in an implementation specific manner, the
458 * object store MUST return STATUS_INVALID_OWNER.
460 token = get_current_nttok(fsp->conn);
461 if (!security_token_is_sid(token, psd->owner_sid)) {
462 return NT_STATUS_INVALID_OWNER;
465 DBG_DEBUG("overriding chown on file %s for sid %s\n",
466 fsp_str_dbg(fsp),
467 dom_sid_str_buf(psd->owner_sid, &buf));
469 status = smb_set_nt_acl_nfs4(handle,
470 fsp,
471 &config->nfs4_params,
472 security_info_sent,
473 psd,
474 nfs4acl_smb4acl_set_fn);
475 return status;
478 static int nfs4acl_connect(struct vfs_handle_struct *handle,
479 const char *service,
480 const char *user)
482 const struct loadparm_substitution *lp_sub =
483 loadparm_s3_global_substitution();
484 struct nfs4acl_config *config = NULL;
485 const struct enum_list *default_acl_style_list = NULL;
486 const char *default_xattr_name = NULL;
487 bool default_validate_mode = true;
488 int enumval;
489 unsigned nfs_version;
490 int ret;
492 default_acl_style_list = get_default_acl_style_list();
494 config = talloc_zero(handle->conn, struct nfs4acl_config);
495 if (config == NULL) {
496 DBG_ERR("talloc_zero() failed\n");
497 return -1;
500 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
501 if (ret < 0) {
502 TALLOC_FREE(config);
503 return ret;
506 ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
507 if (ret < 0) {
508 TALLOC_FREE(config);
509 return ret;
512 enumval = lp_parm_enum(SNUM(handle->conn),
513 "nfs4acl_xattr",
514 "encoding",
515 nfs4acl_encoding,
516 NFS4ACL_ENCODING_NDR);
517 if (enumval == -1) {
518 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
519 return -1;
521 config->encoding = (enum nfs4acl_encoding)enumval;
523 switch (config->encoding) {
524 case NFS4ACL_ENCODING_XDR:
525 default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
526 break;
527 case NFS4ACL_ENCODING_NFS:
528 default_xattr_name = NFS4ACL_NFS_XATTR_NAME;
529 default_validate_mode = false;
530 break;
531 case NFS4ACL_ENCODING_NDR:
532 default:
533 default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
534 break;
537 nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
538 "nfs4acl_xattr",
539 "version",
540 41);
541 switch (nfs_version) {
542 case 40:
543 config->nfs_version = ACL4_XATTR_VERSION_40;
544 break;
545 case 41:
546 config->nfs_version = ACL4_XATTR_VERSION_41;
547 break;
548 default:
549 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
550 break;
553 config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
554 "nfs4acl_xattr",
555 "default acl style",
556 default_acl_style_list,
557 DEFAULT_ACL_EVERYONE);
559 config->xattr_name = lp_parm_substituted_string(config, lp_sub,
560 SNUM(handle->conn),
561 "nfs4acl_xattr",
562 "xattr_name",
563 default_xattr_name);
565 config->nfs4_id_numeric = lp_parm_bool(SNUM(handle->conn),
566 "nfs4acl_xattr",
567 "nfs4_id_numeric",
568 false);
571 config->validate_mode = lp_parm_bool(SNUM(handle->conn),
572 "nfs4acl_xattr",
573 "validate_mode",
574 default_validate_mode);
576 SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
577 return -1);
580 * Ensure we have the parameters correct if we're using this module.
582 DBG_NOTICE("Setting 'inherit acls = true', "
583 "'dos filemode = true', "
584 "'force unknown acl user = true', "
585 "'create mask = 0666', "
586 "'directory mask = 0777' and "
587 "'store dos attributes = yes' "
588 "for service [%s]\n", service);
590 lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
591 lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
592 lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
593 lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
594 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
595 lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
597 return 0;
601 As long as Samba does not support an exiplicit method for a module
602 to define conflicting vfs methods, we should override all conflicting
603 methods here. That way, we know we are using the NFSv4 storage
605 Function declarations taken from vfs_solarisacl
608 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
609 const struct smb_filename *smb_fname,
610 SMB_ACL_TYPE_T type,
611 TALLOC_CTX *mem_ctx)
613 return (SMB_ACL_T)NULL;
616 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
617 files_struct *fsp,
618 TALLOC_CTX *mem_ctx)
620 return (SMB_ACL_T)NULL;
623 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
624 const struct smb_filename *smb_fname,
625 SMB_ACL_TYPE_T type,
626 SMB_ACL_T theacl)
628 return -1;
631 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
632 files_struct *fsp,
633 SMB_ACL_T theacl)
635 return -1;
638 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
639 const struct smb_filename *smb_fname)
641 return -1;
644 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
645 const struct smb_filename *smb_fname,
646 TALLOC_CTX *mem_ctx,
647 char **blob_description,
648 DATA_BLOB *blob)
650 return -1;
653 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)
655 return -1;
658 /* VFS operations structure */
660 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
661 .connect_fn = nfs4acl_connect,
662 .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
663 .get_nt_acl_at_fn = nfs4acl_xattr_get_nt_acl_at,
664 .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
666 .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
667 .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
668 .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
669 .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
670 .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
671 .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
672 .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
675 static_decl_vfs;
676 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
678 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
679 &nfs4acl_xattr_fns);