vfs_glusterfs: Use glfs_readlinkat() for SMB_VFS_READLINKAT
[Samba.git] / source3 / modules / vfs_nfs4acl_xattr.c
blobcecafcf50b8d85b9ad4fa273060a3fc97ffa2c16
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 files_struct *fsp)
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 (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
70 expected_mode = 0777;
71 } else {
72 expected_mode = 0666;
74 if ((fsp->fsp_name->st.st_ex_mode & expected_mode) == expected_mode) {
75 return true;
78 ret = SMB_VFS_NEXT_FREMOVEXATTR(handle,
79 fsp,
80 config->xattr_name);
81 if (ret != 0 && errno != ENOATTR) {
82 DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno));
83 return false;
86 return true;
89 static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
90 files_struct *fsp,
91 TALLOC_CTX *mem_ctx,
92 DATA_BLOB *blob)
94 struct nfs4acl_config *config = NULL;
95 size_t allocsize = 256;
96 ssize_t length;
97 bool ok;
99 SMB_VFS_HANDLE_GET_DATA(handle, config,
100 struct nfs4acl_config,
101 return NT_STATUS_INTERNAL_ERROR);
103 *blob = data_blob_null;
105 ok = nfs4acl_validate_blob(handle, fsp);
106 if (!ok) {
107 return NT_STATUS_INTERNAL_ERROR;
110 do {
112 allocsize *= 4;
113 ok = data_blob_realloc(mem_ctx, blob, allocsize);
114 if (!ok) {
115 return NT_STATUS_NO_MEMORY;
118 length = SMB_VFS_NEXT_FGETXATTR(handle,
119 fsp,
120 config->xattr_name,
121 blob->data,
122 blob->length);
123 } while (length == -1 && errno == ERANGE && allocsize <= 65536);
125 if (length == -1) {
126 return map_nt_error_from_unix(errno);
129 return NT_STATUS_OK;
132 static NTSTATUS nfs4acl_xattr_default_sd(
133 struct vfs_handle_struct *handle,
134 const struct smb_filename *smb_fname,
135 TALLOC_CTX *mem_ctx,
136 struct security_descriptor **sd)
138 struct nfs4acl_config *config = NULL;
139 enum default_acl_style default_acl_style;
140 mode_t required_mode;
141 SMB_STRUCT_STAT sbuf = smb_fname->st;
142 int ret;
144 SMB_VFS_HANDLE_GET_DATA(handle, config,
145 struct nfs4acl_config,
146 return NT_STATUS_INTERNAL_ERROR);
148 default_acl_style = config->default_acl_style;
150 if (!VALID_STAT(sbuf)) {
151 ret = vfs_stat_smb_basename(handle->conn,
152 smb_fname,
153 &sbuf);
154 if (ret != 0) {
155 return map_nt_error_from_unix(errno);
159 if (S_ISDIR(sbuf.st_ex_mode)) {
160 required_mode = 0777;
161 } else {
162 required_mode = 0666;
164 if ((sbuf.st_ex_mode & required_mode) != required_mode) {
165 default_acl_style = DEFAULT_ACL_POSIX;
168 return make_default_filesystem_acl(mem_ctx,
169 default_acl_style,
170 smb_fname->base_name,
171 &sbuf,
172 sd);
175 static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
176 DATA_BLOB *blob,
177 TALLOC_CTX *mem_ctx,
178 struct SMB4ACL_T **smb4acl)
180 struct nfs4acl_config *config = NULL;
181 NTSTATUS status;
183 SMB_VFS_HANDLE_GET_DATA(handle, config,
184 struct nfs4acl_config,
185 return NT_STATUS_INTERNAL_ERROR);
187 switch (config->encoding) {
188 case NFS4ACL_ENCODING_NDR:
189 status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
190 break;
191 case NFS4ACL_ENCODING_XDR:
192 status = nfs4acl_xdr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
193 break;
194 case NFS4ACL_ENCODING_NFS:
195 status = nfs4acl_nfs_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
196 break;
197 default:
198 status = NT_STATUS_INTERNAL_ERROR;
199 break;
202 return status;
205 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
206 struct files_struct *fsp,
207 uint32_t security_info,
208 TALLOC_CTX *mem_ctx,
209 struct security_descriptor **sd)
211 struct SMB4ACL_T *smb4acl = NULL;
212 TALLOC_CTX *frame = talloc_stackframe();
213 DATA_BLOB blob;
214 NTSTATUS status;
216 status = nfs4acl_get_blob(handle, fsp, frame, &blob);
217 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
218 TALLOC_FREE(frame);
219 return nfs4acl_xattr_default_sd(
220 handle, fsp->fsp_name, mem_ctx, sd);
222 if (!NT_STATUS_IS_OK(status)) {
223 TALLOC_FREE(frame);
224 return status;
227 status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
228 if (!NT_STATUS_IS_OK(status)) {
229 TALLOC_FREE(frame);
230 return status;
233 status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
234 sd, smb4acl);
235 TALLOC_FREE(frame);
236 return status;
239 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
240 files_struct *fsp,
241 struct SMB4ACL_T *smb4acl)
243 struct nfs4acl_config *config = NULL;
244 DATA_BLOB blob;
245 NTSTATUS status;
246 int saved_errno = 0;
247 int ret;
249 SMB_VFS_HANDLE_GET_DATA(handle, config,
250 struct nfs4acl_config,
251 return false);
253 switch (config->encoding) {
254 case NFS4ACL_ENCODING_NDR:
255 status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
256 smb4acl, &blob);
257 break;
258 case NFS4ACL_ENCODING_XDR:
259 status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
260 smb4acl, &blob);
261 break;
262 case NFS4ACL_ENCODING_NFS:
263 status = nfs4acl_smb4acl_to_nfs_blob(handle, talloc_tos(),
264 smb4acl, &blob);
265 break;
266 default:
267 status = NT_STATUS_INTERNAL_ERROR;
268 break;
270 if (!NT_STATUS_IS_OK(status)) {
271 return false;
274 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
275 blob.data, blob.length, 0);
276 if (ret != 0) {
277 saved_errno = errno;
279 data_blob_free(&blob);
280 if (saved_errno != 0) {
281 errno = saved_errno;
283 if (ret != 0) {
284 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
285 return false;
288 return true;
291 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
292 files_struct *fsp,
293 uint32_t security_info_sent,
294 const struct security_descriptor *psd)
296 struct nfs4acl_config *config = NULL;
297 const struct security_token *token = NULL;
298 mode_t existing_mode;
299 mode_t expected_mode;
300 mode_t restored_mode;
301 bool chown_needed = false;
302 struct dom_sid_buf buf;
303 NTSTATUS status;
304 int ret;
306 SMB_VFS_HANDLE_GET_DATA(handle, config,
307 struct nfs4acl_config,
308 return NT_STATUS_INTERNAL_ERROR);
310 if (!VALID_STAT(fsp->fsp_name->st)) {
311 DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
312 return NT_STATUS_INTERNAL_ERROR;
315 existing_mode = fsp->fsp_name->st.st_ex_mode;
316 if (S_ISDIR(existing_mode)) {
317 expected_mode = 0777;
318 } else {
319 expected_mode = 0666;
321 if (!config->validate_mode) {
322 existing_mode = 0;
323 expected_mode = 0;
325 if ((existing_mode & expected_mode) != expected_mode) {
327 restored_mode = existing_mode | expected_mode;
329 ret = SMB_VFS_NEXT_FCHMOD(handle,
330 fsp,
331 restored_mode);
332 if (ret != 0) {
333 DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
334 fsp_str_dbg(fsp), existing_mode,
335 strerror(errno));
336 return map_nt_error_from_unix(errno);
340 status = smb_set_nt_acl_nfs4(handle,
341 fsp,
342 &config->nfs4_params,
343 security_info_sent,
344 psd,
345 nfs4acl_smb4acl_set_fn);
346 if (NT_STATUS_IS_OK(status)) {
347 return NT_STATUS_OK;
349 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
350 return status;
354 * We got access denied. If we're already root, or we didn't
355 * need to do a chown, or the fsp isn't open with WRITE_OWNER
356 * access, just return.
359 if ((security_info_sent & SECINFO_OWNER) &&
360 (psd->owner_sid != NULL))
362 chown_needed = true;
364 if ((security_info_sent & SECINFO_GROUP) &&
365 (psd->group_sid != NULL))
367 chown_needed = true;
370 if (get_current_uid(handle->conn) == 0 ||
371 chown_needed == false ||
372 !(fsp->access_mask & SEC_STD_WRITE_OWNER))
374 return NT_STATUS_ACCESS_DENIED;
378 * Only allow take-ownership, not give-ownership. That's the way Windows
379 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
380 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
381 * objectstore, as determined in an implementation specific manner, the
382 * object store MUST return STATUS_INVALID_OWNER.
384 token = get_current_nttok(fsp->conn);
385 if (!security_token_is_sid(token, psd->owner_sid)) {
386 return NT_STATUS_INVALID_OWNER;
389 DBG_DEBUG("overriding chown on file %s for sid %s\n",
390 fsp_str_dbg(fsp),
391 dom_sid_str_buf(psd->owner_sid, &buf));
393 status = smb_set_nt_acl_nfs4(handle,
394 fsp,
395 &config->nfs4_params,
396 security_info_sent,
397 psd,
398 nfs4acl_smb4acl_set_fn);
399 return status;
402 static int nfs4acl_connect(struct vfs_handle_struct *handle,
403 const char *service,
404 const char *user)
406 const struct loadparm_substitution *lp_sub =
407 loadparm_s3_global_substitution();
408 struct nfs4acl_config *config = NULL;
409 const struct enum_list *default_acl_style_list = NULL;
410 const char *default_xattr_name = NULL;
411 bool default_validate_mode = true;
412 int enumval;
413 unsigned nfs_version;
414 int ret;
416 default_acl_style_list = get_default_acl_style_list();
418 config = talloc_zero(handle->conn, struct nfs4acl_config);
419 if (config == NULL) {
420 DBG_ERR("talloc_zero() failed\n");
421 return -1;
424 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
425 if (ret < 0) {
426 TALLOC_FREE(config);
427 return ret;
430 ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
431 if (ret < 0) {
432 TALLOC_FREE(config);
433 return ret;
436 enumval = lp_parm_enum(SNUM(handle->conn),
437 "nfs4acl_xattr",
438 "encoding",
439 nfs4acl_encoding,
440 NFS4ACL_ENCODING_NDR);
441 if (enumval == -1) {
442 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
443 return -1;
445 config->encoding = (enum nfs4acl_encoding)enumval;
447 switch (config->encoding) {
448 case NFS4ACL_ENCODING_XDR:
449 default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
450 break;
451 case NFS4ACL_ENCODING_NFS:
452 default_xattr_name = NFS4ACL_NFS_XATTR_NAME;
453 default_validate_mode = false;
454 break;
455 case NFS4ACL_ENCODING_NDR:
456 default:
457 default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
458 break;
461 nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
462 "nfs4acl_xattr",
463 "version",
464 41);
465 switch (nfs_version) {
466 case 40:
467 config->nfs_version = ACL4_XATTR_VERSION_40;
468 break;
469 case 41:
470 config->nfs_version = ACL4_XATTR_VERSION_41;
471 break;
472 default:
473 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
474 break;
477 config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
478 "nfs4acl_xattr",
479 "default acl style",
480 default_acl_style_list,
481 DEFAULT_ACL_EVERYONE);
483 config->xattr_name = lp_parm_substituted_string(config, lp_sub,
484 SNUM(handle->conn),
485 "nfs4acl_xattr",
486 "xattr_name",
487 default_xattr_name);
489 config->nfs4_id_numeric = lp_parm_bool(SNUM(handle->conn),
490 "nfs4acl_xattr",
491 "nfs4_id_numeric",
492 false);
495 config->validate_mode = lp_parm_bool(SNUM(handle->conn),
496 "nfs4acl_xattr",
497 "validate_mode",
498 default_validate_mode);
500 SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
501 return -1);
504 * Ensure we have the parameters correct if we're using this module.
506 DBG_NOTICE("Setting 'inherit acls = true', "
507 "'dos filemode = true', "
508 "'force unknown acl user = true', "
509 "'create mask = 0666', "
510 "'directory mask = 0777' and "
511 "'store dos attributes = yes' "
512 "for service [%s]\n", service);
514 lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
515 lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
516 lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
517 lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
518 lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
519 lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
521 return 0;
525 As long as Samba does not support an exiplicit method for a module
526 to define conflicting vfs methods, we should override all conflicting
527 methods here. That way, we know we are using the NFSv4 storage
529 Function declarations taken from vfs_solarisacl
532 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
533 files_struct *fsp,
534 SMB_ACL_TYPE_T type,
535 TALLOC_CTX *mem_ctx)
537 return (SMB_ACL_T)NULL;
540 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
541 files_struct *fsp,
542 SMB_ACL_TYPE_T type,
543 SMB_ACL_T theacl)
545 return -1;
548 static int nfs4acl_xattr_fail__sys_acl_delete_def_fd(vfs_handle_struct *handle,
549 files_struct *fsp)
551 return -1;
554 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)
556 return -1;
559 /* VFS operations structure */
561 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
562 .connect_fn = nfs4acl_connect,
563 .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
564 .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
566 .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
567 .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
568 .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
569 .sys_acl_delete_def_fd_fn = nfs4acl_xattr_fail__sys_acl_delete_def_fd,
572 static_decl_vfs;
573 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
575 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
576 &nfs4acl_xattr_fns);