Line data Source code
1 : /*
2 : * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ to NT acls and vice versa.
3 : *
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
7 : *
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
13 : *
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.
18 : *
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.
23 : *
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/>.
26 : *
27 : */
28 :
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"
40 :
41 : #undef DBGC_CLASS
42 : #define DBGC_CLASS DBGC_VFS
43 :
44 : static const struct enum_list nfs4acl_encoding[] = {
45 : {NFS4ACL_ENCODING_NDR, "ndr"},
46 : {NFS4ACL_ENCODING_XDR, "xdr"},
47 : {NFS4ACL_ENCODING_NFS, "nfs"},
48 : };
49 :
50 : /*
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.
53 : */
54 11984 : static bool nfs4acl_validate_blob(vfs_handle_struct *handle,
55 : files_struct *fsp)
56 : {
57 11984 : struct nfs4acl_config *config = NULL;
58 : mode_t expected_mode;
59 : int ret;
60 :
61 11984 : SMB_VFS_HANDLE_GET_DATA(handle, config,
62 : struct nfs4acl_config,
63 : return false);
64 :
65 11984 : if (!config->validate_mode) {
66 3424 : return true;
67 : }
68 :
69 8560 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
70 4570 : expected_mode = 0777;
71 : } else {
72 3990 : expected_mode = 0666;
73 : }
74 8560 : if ((fsp->fsp_name->st.st_ex_mode & expected_mode) == expected_mode) {
75 8560 : return true;
76 : }
77 :
78 0 : ret = SMB_VFS_NEXT_FREMOVEXATTR(handle,
79 : fsp,
80 : config->xattr_name);
81 0 : if (ret != 0 && errno != ENOATTR) {
82 0 : DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno));
83 0 : return false;
84 : }
85 :
86 0 : return true;
87 : }
88 :
89 11984 : static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
90 : files_struct *fsp,
91 : TALLOC_CTX *mem_ctx,
92 : DATA_BLOB *blob)
93 : {
94 11984 : struct nfs4acl_config *config = NULL;
95 11984 : size_t allocsize = 256;
96 : ssize_t length;
97 : bool ok;
98 :
99 11984 : SMB_VFS_HANDLE_GET_DATA(handle, config,
100 : struct nfs4acl_config,
101 : return NT_STATUS_INTERNAL_ERROR);
102 :
103 11984 : *blob = data_blob_null;
104 :
105 11984 : ok = nfs4acl_validate_blob(handle, fsp);
106 11984 : if (!ok) {
107 0 : return NT_STATUS_INTERNAL_ERROR;
108 : }
109 :
110 : do {
111 :
112 11984 : allocsize *= 4;
113 11984 : ok = data_blob_realloc(mem_ctx, blob, allocsize);
114 11984 : if (!ok) {
115 0 : return NT_STATUS_NO_MEMORY;
116 : }
117 :
118 11984 : length = SMB_VFS_NEXT_FGETXATTR(handle,
119 : fsp,
120 : config->xattr_name,
121 : blob->data,
122 : blob->length);
123 11984 : } while (length == -1 && errno == ERANGE && allocsize <= 65536);
124 :
125 11984 : if (length == -1) {
126 3220 : return map_nt_error_from_unix(errno);
127 : }
128 :
129 8764 : return NT_STATUS_OK;
130 : }
131 :
132 3220 : 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)
137 : {
138 3220 : struct nfs4acl_config *config = NULL;
139 : enum default_acl_style default_acl_style;
140 : mode_t required_mode;
141 3220 : SMB_STRUCT_STAT sbuf = smb_fname->st;
142 : int ret;
143 :
144 3220 : SMB_VFS_HANDLE_GET_DATA(handle, config,
145 : struct nfs4acl_config,
146 : return NT_STATUS_INTERNAL_ERROR);
147 :
148 3220 : default_acl_style = config->default_acl_style;
149 :
150 3220 : if (!VALID_STAT(sbuf)) {
151 0 : ret = vfs_stat_smb_basename(handle->conn,
152 : smb_fname,
153 : &sbuf);
154 0 : if (ret != 0) {
155 0 : return map_nt_error_from_unix(errno);
156 : }
157 : }
158 :
159 3220 : if (S_ISDIR(sbuf.st_ex_mode)) {
160 2842 : required_mode = 0777;
161 : } else {
162 378 : required_mode = 0666;
163 : }
164 3220 : if ((sbuf.st_ex_mode & required_mode) != required_mode) {
165 0 : default_acl_style = DEFAULT_ACL_POSIX;
166 : }
167 :
168 3220 : return make_default_filesystem_acl(mem_ctx,
169 : default_acl_style,
170 3220 : smb_fname->base_name,
171 : &sbuf,
172 : sd);
173 : }
174 :
175 8764 : 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)
179 : {
180 8764 : struct nfs4acl_config *config = NULL;
181 : NTSTATUS status;
182 :
183 8764 : SMB_VFS_HANDLE_GET_DATA(handle, config,
184 : struct nfs4acl_config,
185 : return NT_STATUS_INTERNAL_ERROR);
186 :
187 8764 : switch (config->encoding) {
188 3756 : case NFS4ACL_ENCODING_NDR:
189 3756 : status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
190 3756 : break;
191 2504 : case NFS4ACL_ENCODING_XDR:
192 2504 : status = nfs4acl_xdr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
193 2504 : break;
194 2504 : case NFS4ACL_ENCODING_NFS:
195 2504 : status = nfs4acl_nfs_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
196 2504 : break;
197 0 : default:
198 0 : status = NT_STATUS_INTERNAL_ERROR;
199 0 : break;
200 : }
201 :
202 8764 : return status;
203 : }
204 :
205 11984 : 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)
210 : {
211 11984 : struct SMB4ACL_T *smb4acl = NULL;
212 11984 : TALLOC_CTX *frame = talloc_stackframe();
213 : DATA_BLOB blob;
214 : NTSTATUS status;
215 :
216 11984 : status = nfs4acl_get_blob(handle, fsp, frame, &blob);
217 11984 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
218 3220 : TALLOC_FREE(frame);
219 3220 : return nfs4acl_xattr_default_sd(
220 3220 : handle, fsp->fsp_name, mem_ctx, sd);
221 : }
222 8764 : if (!NT_STATUS_IS_OK(status)) {
223 0 : TALLOC_FREE(frame);
224 0 : return status;
225 : }
226 :
227 8764 : status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
228 8764 : if (!NT_STATUS_IS_OK(status)) {
229 0 : TALLOC_FREE(frame);
230 0 : return status;
231 : }
232 :
233 8764 : status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
234 : sd, smb4acl);
235 8764 : TALLOC_FREE(frame);
236 8764 : return status;
237 : }
238 :
239 4998 : static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
240 : files_struct *fsp,
241 : struct SMB4ACL_T *smb4acl)
242 : {
243 4998 : struct nfs4acl_config *config = NULL;
244 : DATA_BLOB blob;
245 : NTSTATUS status;
246 4998 : int saved_errno = 0;
247 : int ret;
248 :
249 4998 : SMB_VFS_HANDLE_GET_DATA(handle, config,
250 : struct nfs4acl_config,
251 : return false);
252 :
253 4998 : switch (config->encoding) {
254 2142 : case NFS4ACL_ENCODING_NDR:
255 2142 : status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
256 : smb4acl, &blob);
257 2142 : break;
258 1428 : case NFS4ACL_ENCODING_XDR:
259 1428 : status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
260 : smb4acl, &blob);
261 1428 : break;
262 1428 : case NFS4ACL_ENCODING_NFS:
263 1428 : status = nfs4acl_smb4acl_to_nfs_blob(handle, talloc_tos(),
264 : smb4acl, &blob);
265 1428 : break;
266 0 : default:
267 0 : status = NT_STATUS_INTERNAL_ERROR;
268 0 : break;
269 : }
270 4998 : if (!NT_STATUS_IS_OK(status)) {
271 0 : return false;
272 : }
273 :
274 4998 : ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
275 : blob.data, blob.length, 0);
276 4998 : if (ret != 0) {
277 0 : saved_errno = errno;
278 : }
279 4998 : data_blob_free(&blob);
280 4998 : if (saved_errno != 0) {
281 0 : errno = saved_errno;
282 : }
283 4998 : if (ret != 0) {
284 0 : DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
285 0 : return false;
286 : }
287 :
288 4998 : return true;
289 : }
290 :
291 5012 : 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)
295 : {
296 5012 : struct nfs4acl_config *config = NULL;
297 5012 : const struct security_token *token = NULL;
298 : mode_t existing_mode;
299 : mode_t expected_mode;
300 : mode_t restored_mode;
301 5012 : bool chown_needed = false;
302 : struct dom_sid_buf buf;
303 : NTSTATUS status;
304 : int ret;
305 :
306 5012 : SMB_VFS_HANDLE_GET_DATA(handle, config,
307 : struct nfs4acl_config,
308 : return NT_STATUS_INTERNAL_ERROR);
309 :
310 5012 : if (!VALID_STAT(fsp->fsp_name->st)) {
311 0 : DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
312 0 : return NT_STATUS_INTERNAL_ERROR;
313 : }
314 :
315 5012 : existing_mode = fsp->fsp_name->st.st_ex_mode;
316 5012 : if (S_ISDIR(existing_mode)) {
317 784 : expected_mode = 0777;
318 : } else {
319 4228 : expected_mode = 0666;
320 : }
321 5012 : if (!config->validate_mode) {
322 1432 : existing_mode = 0;
323 1432 : expected_mode = 0;
324 : }
325 5012 : if ((existing_mode & expected_mode) != expected_mode) {
326 :
327 0 : restored_mode = existing_mode | expected_mode;
328 :
329 0 : ret = SMB_VFS_NEXT_FCHMOD(handle,
330 : fsp,
331 : restored_mode);
332 0 : if (ret != 0) {
333 0 : DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
334 : fsp_str_dbg(fsp), existing_mode,
335 : strerror(errno));
336 0 : return map_nt_error_from_unix(errno);
337 : }
338 : }
339 :
340 5012 : status = smb_set_nt_acl_nfs4(handle,
341 : fsp,
342 5012 : &config->nfs4_params,
343 : security_info_sent,
344 : psd,
345 : nfs4acl_smb4acl_set_fn);
346 5012 : if (NT_STATUS_IS_OK(status)) {
347 5012 : return NT_STATUS_OK;
348 : }
349 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
350 0 : return status;
351 : }
352 :
353 : /*
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.
357 : */
358 :
359 0 : if ((security_info_sent & SECINFO_OWNER) &&
360 0 : (psd->owner_sid != NULL))
361 : {
362 0 : chown_needed = true;
363 : }
364 0 : if ((security_info_sent & SECINFO_GROUP) &&
365 0 : (psd->group_sid != NULL))
366 : {
367 0 : chown_needed = true;
368 : }
369 :
370 0 : if (get_current_uid(handle->conn) == 0 ||
371 0 : chown_needed == false ||
372 0 : !(fsp->access_mask & SEC_STD_WRITE_OWNER))
373 : {
374 0 : return NT_STATUS_ACCESS_DENIED;
375 : }
376 :
377 : /*
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.
383 : */
384 0 : token = get_current_nttok(fsp->conn);
385 0 : if (!security_token_is_sid(token, psd->owner_sid)) {
386 0 : return NT_STATUS_INVALID_OWNER;
387 : }
388 :
389 0 : 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));
392 :
393 0 : status = smb_set_nt_acl_nfs4(handle,
394 : fsp,
395 0 : &config->nfs4_params,
396 : security_info_sent,
397 : psd,
398 : nfs4acl_smb4acl_set_fn);
399 0 : return status;
400 : }
401 :
402 212 : static int nfs4acl_connect(struct vfs_handle_struct *handle,
403 : const char *service,
404 : const char *user)
405 : {
406 : const struct loadparm_substitution *lp_sub =
407 212 : loadparm_s3_global_substitution();
408 212 : struct nfs4acl_config *config = NULL;
409 212 : const struct enum_list *default_acl_style_list = NULL;
410 212 : const char *default_xattr_name = NULL;
411 212 : bool default_validate_mode = true;
412 : int enumval;
413 : unsigned nfs_version;
414 : int ret;
415 :
416 212 : default_acl_style_list = get_default_acl_style_list();
417 :
418 212 : config = talloc_zero(handle->conn, struct nfs4acl_config);
419 212 : if (config == NULL) {
420 0 : DBG_ERR("talloc_zero() failed\n");
421 0 : return -1;
422 : }
423 :
424 212 : ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
425 212 : if (ret < 0) {
426 0 : TALLOC_FREE(config);
427 0 : return ret;
428 : }
429 :
430 212 : ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
431 212 : if (ret < 0) {
432 0 : TALLOC_FREE(config);
433 0 : return ret;
434 : }
435 :
436 212 : enumval = lp_parm_enum(SNUM(handle->conn),
437 : "nfs4acl_xattr",
438 : "encoding",
439 : nfs4acl_encoding,
440 : NFS4ACL_ENCODING_NDR);
441 212 : if (enumval == -1) {
442 0 : DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
443 0 : return -1;
444 : }
445 212 : config->encoding = (enum nfs4acl_encoding)enumval;
446 :
447 212 : switch (config->encoding) {
448 60 : case NFS4ACL_ENCODING_XDR:
449 60 : default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
450 60 : break;
451 60 : case NFS4ACL_ENCODING_NFS:
452 60 : default_xattr_name = NFS4ACL_NFS_XATTR_NAME;
453 60 : default_validate_mode = false;
454 60 : break;
455 92 : case NFS4ACL_ENCODING_NDR:
456 : default:
457 92 : default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
458 92 : break;
459 : }
460 :
461 212 : nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
462 : "nfs4acl_xattr",
463 : "version",
464 : 41);
465 212 : switch (nfs_version) {
466 122 : case 40:
467 122 : config->nfs_version = ACL4_XATTR_VERSION_40;
468 122 : break;
469 90 : case 41:
470 90 : config->nfs_version = ACL4_XATTR_VERSION_41;
471 90 : break;
472 0 : default:
473 0 : config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
474 0 : break;
475 : }
476 :
477 212 : 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);
482 :
483 212 : config->xattr_name = lp_parm_substituted_string(config, lp_sub,
484 212 : SNUM(handle->conn),
485 : "nfs4acl_xattr",
486 : "xattr_name",
487 : default_xattr_name);
488 :
489 212 : config->nfs4_id_numeric = lp_parm_bool(SNUM(handle->conn),
490 : "nfs4acl_xattr",
491 : "nfs4_id_numeric",
492 : false);
493 :
494 :
495 212 : config->validate_mode = lp_parm_bool(SNUM(handle->conn),
496 : "nfs4acl_xattr",
497 : "validate_mode",
498 : default_validate_mode);
499 :
500 212 : SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
501 : return -1);
502 :
503 : /*
504 : * Ensure we have the parameters correct if we're using this module.
505 : */
506 212 : 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);
513 :
514 212 : lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
515 212 : lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
516 212 : lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
517 212 : lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
518 212 : lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
519 212 : lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
520 :
521 212 : return 0;
522 : }
523 :
524 : /*
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
528 :
529 : Function declarations taken from vfs_solarisacl
530 : */
531 :
532 1134 : 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)
536 : {
537 1134 : return (SMB_ACL_T)NULL;
538 : }
539 :
540 0 : 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)
544 : {
545 0 : return -1;
546 : }
547 :
548 0 : static int nfs4acl_xattr_fail__sys_acl_delete_def_fd(vfs_handle_struct *handle,
549 : files_struct *fsp)
550 : {
551 0 : return -1;
552 : }
553 :
554 0 : 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)
555 : {
556 0 : return -1;
557 : }
558 :
559 : /* VFS operations structure */
560 :
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,
565 :
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,
570 : };
571 :
572 : static_decl_vfs;
573 203 : NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
574 : {
575 203 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
576 : &nfs4acl_xattr_fns);
577 : }
|