s4:selftest: explicitly set NSS/RESOLV_WAPPER_* in wait_for_start
[Samba.git] / source3 / modules / vfs_nfs4acl_xattr.c
blob0e52782075be97b04ca7f3dd4fe2ed8b0bcde165
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 "nfs4_acls.h"
34 #include "librpc/gen_ndr/ndr_nfs4acl.h"
35 #include "nfs4acl_xattr.h"
36 #include "nfs4acl_xattr_ndr.h"
37 #include "nfs4acl_xattr_xdr.h"
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_VFS
42 static const struct enum_list nfs4acl_encoding[] = {
43 {NFS4ACL_ENCODING_NDR, "ndr"},
44 {NFS4ACL_ENCODING_XDR, "xdr"},
48 * Check if someone changed the POSIX mode, for files we expect 0666, for
49 * directories 0777. Discard the ACL blob if the mode is different.
51 static bool nfs4acl_validate_blob(vfs_handle_struct *handle,
52 const struct smb_filename *smb_fname)
54 struct nfs4acl_config *config = NULL;
55 mode_t expected_mode;
56 int saved_errno = 0;
57 int ret;
59 SMB_VFS_HANDLE_GET_DATA(handle, config,
60 struct nfs4acl_config,
61 return false);
63 if (!VALID_STAT(smb_fname->st)) {
64 /* might be a create */
65 return true;
68 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
69 expected_mode = 0777;
70 } else {
71 expected_mode = 0666;
73 if ((smb_fname->st.st_ex_mode & expected_mode) == expected_mode) {
74 return true;
77 become_root();
78 ret = SMB_VFS_NEXT_REMOVEXATTR(handle,
79 smb_fname,
80 config->xattr_name);
81 if (ret != 0) {
82 saved_errno = errno;
84 unbecome_root();
85 if (saved_errno != 0) {
86 errno = saved_errno;
88 if (ret != 0 && errno != ENOATTR) {
89 DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno));
90 return false;
93 return true;
96 static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
97 files_struct *fsp,
98 const struct smb_filename *smb_fname_in,
99 TALLOC_CTX *mem_ctx,
100 DATA_BLOB *blob)
102 struct nfs4acl_config *config = NULL;
103 const struct smb_filename *smb_fname = NULL;
104 size_t allocsize = 256;
105 ssize_t length;
106 bool ok;
108 SMB_VFS_HANDLE_GET_DATA(handle, config,
109 struct nfs4acl_config,
110 return NT_STATUS_INTERNAL_ERROR);
112 *blob = data_blob_null;
114 if (fsp == NULL && smb_fname_in == NULL) {
115 return NT_STATUS_INTERNAL_ERROR;
117 smb_fname = smb_fname_in;
118 if (smb_fname == NULL) {
119 smb_fname = fsp->fsp_name;
121 if (smb_fname == NULL) {
122 return NT_STATUS_INTERNAL_ERROR;
125 ok = nfs4acl_validate_blob(handle, smb_fname);
126 if (!ok) {
127 return NT_STATUS_INTERNAL_ERROR;
130 do {
131 int saved_errno = 0;
133 allocsize *= 4;
134 ok = data_blob_realloc(mem_ctx, blob, allocsize);
135 if (!ok) {
136 return NT_STATUS_NO_MEMORY;
139 become_root();
140 if (fsp != NULL && fsp->fh->fd != -1) {
141 length = SMB_VFS_NEXT_FGETXATTR(handle,
142 fsp,
143 config->xattr_name,
144 blob->data,
145 blob->length);
146 } else {
147 length = SMB_VFS_NEXT_GETXATTR(handle,
148 smb_fname,
149 config->xattr_name,
150 blob->data,
151 blob->length);
153 if (length == -1) {
154 saved_errno = errno;
156 unbecome_root();
157 if (saved_errno != 0) {
158 errno = saved_errno;
160 } while (length == -1 && errno == ERANGE && allocsize <= 65536);
162 if (length == -1) {
163 return map_nt_error_from_unix(errno);
166 return NT_STATUS_OK;
169 static NTSTATUS nfs4acl_xattr_default_sd(
170 struct vfs_handle_struct *handle,
171 const struct smb_filename *smb_fname,
172 TALLOC_CTX *mem_ctx,
173 struct security_descriptor **sd)
175 struct nfs4acl_config *config = NULL;
176 enum default_acl_style default_acl_style;
177 mode_t required_mode;
178 SMB_STRUCT_STAT sbuf = smb_fname->st;
179 int ret;
181 SMB_VFS_HANDLE_GET_DATA(handle, config,
182 struct nfs4acl_config,
183 return NT_STATUS_INTERNAL_ERROR);
185 default_acl_style = config->default_acl_style;
187 if (!VALID_STAT(sbuf)) {
188 ret = vfs_stat_smb_basename(handle->conn,
189 smb_fname,
190 &sbuf);
191 if (ret != 0) {
192 return map_nt_error_from_unix(errno);
196 if (S_ISDIR(sbuf.st_ex_mode)) {
197 required_mode = 0777;
198 } else {
199 required_mode = 0666;
201 if ((sbuf.st_ex_mode & required_mode) != required_mode) {
202 default_acl_style = DEFAULT_ACL_POSIX;
205 return make_default_filesystem_acl(mem_ctx,
206 default_acl_style,
207 smb_fname->base_name,
208 &sbuf,
209 sd);
212 static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
213 DATA_BLOB *blob,
214 TALLOC_CTX *mem_ctx,
215 struct SMB4ACL_T **smb4acl)
217 struct nfs4acl_config *config = NULL;
218 NTSTATUS status;
220 SMB_VFS_HANDLE_GET_DATA(handle, config,
221 struct nfs4acl_config,
222 return NT_STATUS_INTERNAL_ERROR);
224 switch (config->encoding) {
225 case NFS4ACL_ENCODING_NDR:
226 status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
227 break;
228 case NFS4ACL_ENCODING_XDR:
229 status = nfs4acl_xdr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
230 break;
231 default:
232 status = NT_STATUS_INTERNAL_ERROR;
233 break;
236 return status;
239 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
240 struct files_struct *fsp,
241 uint32_t security_info,
242 TALLOC_CTX *mem_ctx,
243 struct security_descriptor **sd)
245 struct SMB4ACL_T *smb4acl = NULL;
246 TALLOC_CTX *frame = talloc_stackframe();
247 DATA_BLOB blob;
248 NTSTATUS status;
250 status = nfs4acl_get_blob(handle, fsp, NULL, frame, &blob);
251 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
252 TALLOC_FREE(frame);
253 return nfs4acl_xattr_default_sd(
254 handle, fsp->fsp_name, mem_ctx, sd);
256 if (!NT_STATUS_IS_OK(status)) {
257 TALLOC_FREE(frame);
258 return status;
261 status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
262 if (!NT_STATUS_IS_OK(status)) {
263 TALLOC_FREE(frame);
264 return status;
267 status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
268 sd, smb4acl);
269 TALLOC_FREE(frame);
270 return status;
273 static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
274 const struct smb_filename *smb_fname,
275 uint32_t security_info,
276 TALLOC_CTX *mem_ctx,
277 struct security_descriptor **sd)
279 struct SMB4ACL_T *smb4acl = NULL;
280 TALLOC_CTX *frame = talloc_stackframe();
281 DATA_BLOB blob;
282 NTSTATUS status;
284 status = nfs4acl_get_blob(handle, NULL, smb_fname, frame, &blob);
285 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
286 TALLOC_FREE(frame);
287 return nfs4acl_xattr_default_sd(
288 handle, smb_fname, mem_ctx, sd);
290 if (!NT_STATUS_IS_OK(status)) {
291 TALLOC_FREE(frame);
292 return status;
295 status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
296 if (!NT_STATUS_IS_OK(status)) {
297 TALLOC_FREE(frame);
298 return status;
301 status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
302 security_info, mem_ctx, sd,
303 smb4acl);
304 TALLOC_FREE(frame);
305 return status;
308 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
309 files_struct *fsp,
310 struct SMB4ACL_T *smb4acl)
312 struct nfs4acl_config *config = NULL;
313 DATA_BLOB blob;
314 NTSTATUS status;
315 int saved_errno = 0;
316 int ret;
318 SMB_VFS_HANDLE_GET_DATA(handle, config,
319 struct nfs4acl_config,
320 return false);
322 switch (config->encoding) {
323 case NFS4ACL_ENCODING_NDR:
324 status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
325 smb4acl, &blob);
326 break;
327 case NFS4ACL_ENCODING_XDR:
328 status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
329 smb4acl, &blob);
330 break;
331 default:
332 status = NT_STATUS_INTERNAL_ERROR;
333 break;
335 if (!NT_STATUS_IS_OK(status)) {
336 return false;
339 become_root();
340 if (fsp->fh->fd != -1) {
341 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
342 blob.data, blob.length, 0);
343 } else {
344 ret = SMB_VFS_NEXT_SETXATTR(handle, fsp->fsp_name,
345 config->xattr_name,
346 blob.data, blob.length, 0);
348 if (ret != 0) {
349 saved_errno = errno;
351 unbecome_root();
352 data_blob_free(&blob);
353 if (saved_errno != 0) {
354 errno = saved_errno;
356 if (ret != 0) {
357 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
358 return false;
361 return true;
364 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
365 files_struct *fsp,
366 uint32_t security_info_sent,
367 const struct security_descriptor *psd)
369 struct nfs4acl_config *config = NULL;
370 const struct security_token *token = NULL;
371 mode_t existing_mode;
372 mode_t expected_mode;
373 mode_t restored_mode;
374 bool chown_needed = false;
375 NTSTATUS status;
376 int ret;
378 SMB_VFS_HANDLE_GET_DATA(handle, config,
379 struct nfs4acl_config,
380 return NT_STATUS_INTERNAL_ERROR);
382 if (!VALID_STAT(fsp->fsp_name->st)) {
383 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
384 return NT_STATUS_INTERNAL_ERROR;
387 existing_mode = fsp->fsp_name->st.st_ex_mode;
388 if (S_ISDIR(existing_mode)) {
389 expected_mode = 0777;
390 } else {
391 expected_mode = 0666;
393 if ((existing_mode & expected_mode) != expected_mode) {
394 int saved_errno = 0;
396 restored_mode = existing_mode | expected_mode;
398 become_root();
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 saved_errno = errno;
411 unbecome_root();
412 if (saved_errno != 0) {
413 errno = saved_errno;
415 if (ret != 0) {
416 DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
417 fsp_str_dbg(fsp), existing_mode,
418 strerror(errno));
419 return map_nt_error_from_unix(errno);
423 status = smb_set_nt_acl_nfs4(handle,
424 fsp,
425 &config->nfs4_params,
426 security_info_sent,
427 psd,
428 nfs4acl_smb4acl_set_fn);
429 if (NT_STATUS_IS_OK(status)) {
430 return NT_STATUS_OK;
434 * We got access denied. If we're already root, or we didn't
435 * need to do a chown, or the fsp isn't open with WRITE_OWNER
436 * access, just return.
439 if ((security_info_sent & SECINFO_OWNER) &&
440 (psd->owner_sid != NULL))
442 chown_needed = true;
444 if ((security_info_sent & SECINFO_GROUP) &&
445 (psd->group_sid != NULL))
447 chown_needed = true;
450 if (get_current_uid(handle->conn) == 0 ||
451 chown_needed == false ||
452 !(fsp->access_mask & SEC_STD_WRITE_OWNER))
454 return NT_STATUS_ACCESS_DENIED;
458 * Only allow take-ownership, not give-ownership. That's the way Windows
459 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
460 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
461 * objectstore, as determined in an implementation specific manner, the
462 * object store MUST return STATUS_INVALID_OWNER.
464 token = get_current_nttok(fsp->conn);
465 if (!security_token_is_sid(token, psd->owner_sid)) {
466 return NT_STATUS_INVALID_OWNER;
469 DBG_DEBUG("overriding chown on file %s for sid %s\n",
470 fsp_str_dbg(fsp), sid_string_tos(psd->owner_sid));
472 become_root();
473 status = smb_set_nt_acl_nfs4(handle,
474 fsp,
475 &config->nfs4_params,
476 security_info_sent,
477 psd,
478 nfs4acl_smb4acl_set_fn);
479 unbecome_root();
480 return status;
483 static int nfs4acl_connect(struct vfs_handle_struct *handle,
484 const char *service,
485 const char *user)
487 struct nfs4acl_config *config = NULL;
488 const struct enum_list *default_acl_style_list = NULL;
489 const char *default_xattr_name = NULL;
490 int enumval;
491 unsigned nfs_version;
492 int ret;
494 default_acl_style_list = get_default_acl_style_list();
496 config = talloc_zero(handle->conn, struct nfs4acl_config);
497 if (config == NULL) {
498 DBG_ERR("talloc_zero() failed\n");
499 return -1;
502 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
503 if (ret < 0) {
504 TALLOC_FREE(config);
505 return ret;
508 ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
509 if (ret < 0) {
510 TALLOC_FREE(config);
511 return ret;
514 enumval = lp_parm_enum(SNUM(handle->conn),
515 "nfs4acl_xattr",
516 "encoding",
517 nfs4acl_encoding,
518 NFS4ACL_ENCODING_NDR);
519 if (enumval == -1) {
520 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
521 return -1;
523 config->encoding = (enum nfs4acl_encoding)enumval;
525 switch (config->encoding) {
526 case NFS4ACL_ENCODING_XDR:
527 default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
528 break;
529 case NFS4ACL_ENCODING_NDR:
530 default:
531 default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
532 break;
535 nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
536 "nfs4acl_xattr",
537 "version",
538 41);
539 switch (nfs_version) {
540 case 40:
541 config->nfs_version = ACL4_XATTR_VERSION_40;
542 break;
543 case 41:
544 config->nfs_version = ACL4_XATTR_VERSION_41;
545 break;
546 default:
547 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
548 break;
551 config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
552 "nfs4acl_xattr",
553 "default acl style",
554 default_acl_style_list,
555 DEFAULT_ACL_EVERYONE);
557 config->xattr_name = lp_parm_talloc_string(config,
558 SNUM(handle->conn),
559 "nfs4acl_xattr",
560 "xattr_name",
561 default_xattr_name);
563 SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
564 return -1);
567 * Ensure we have the parameters correct if we're using this module.
569 DBG_NOTICE("Setting 'inherit acls = true', "
570 "'dos filemode = true', "
571 "'force unknown acl user = true', "
572 "'create mask = 0666', "
573 "'directory mask = 0777' and "
574 "'store dos attributes = yes' "
575 "for service [%s]\n", service);
577 lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
578 lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
579 lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
580 lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
581 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
582 lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
584 return 0;
588 As long as Samba does not support an exiplicit method for a module
589 to define conflicting vfs methods, we should override all conflicting
590 methods here. That way, we know we are using the NFSv4 storage
592 Function declarations taken from vfs_solarisacl
595 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
596 const struct smb_filename *smb_fname,
597 SMB_ACL_TYPE_T type,
598 TALLOC_CTX *mem_ctx)
600 return (SMB_ACL_T)NULL;
603 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
604 files_struct *fsp,
605 TALLOC_CTX *mem_ctx)
607 return (SMB_ACL_T)NULL;
610 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
611 const struct smb_filename *smb_fname,
612 SMB_ACL_TYPE_T type,
613 SMB_ACL_T theacl)
615 return -1;
618 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
619 files_struct *fsp,
620 SMB_ACL_T theacl)
622 return -1;
625 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
626 const struct smb_filename *smb_fname)
628 return -1;
631 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
632 const struct smb_filename *smb_fname,
633 TALLOC_CTX *mem_ctx,
634 char **blob_description,
635 DATA_BLOB *blob)
637 return -1;
640 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)
642 return -1;
645 /* VFS operations structure */
647 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
648 .connect_fn = nfs4acl_connect,
649 .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
650 .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
651 .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
653 .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
654 .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
655 .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
656 .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
657 .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
658 .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
659 .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
662 static_decl_vfs;
663 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
665 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
666 &nfs4acl_xattr_fns);