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 : {
373 0 : return NT_STATUS_ACCESS_DENIED;
374 : }
375 0 : status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER);
376 0 : if (!NT_STATUS_IS_OK(status)) {
377 0 : return status;
378 : }
379 :
380 : /*
381 : * Only allow take-ownership, not give-ownership. That's the way Windows
382 : * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
383 : * InputBuffer.OwnerSid is not a valid owner SID for a file in the
384 : * objectstore, as determined in an implementation specific manner, the
385 : * object store MUST return STATUS_INVALID_OWNER.
386 : */
387 0 : token = get_current_nttok(fsp->conn);
388 0 : if (!security_token_is_sid(token, psd->owner_sid)) {
389 0 : return NT_STATUS_INVALID_OWNER;
390 : }
391 :
392 0 : DBG_DEBUG("overriding chown on file %s for sid %s\n",
393 : fsp_str_dbg(fsp),
394 : dom_sid_str_buf(psd->owner_sid, &buf));
395 :
396 0 : status = smb_set_nt_acl_nfs4(handle,
397 : fsp,
398 0 : &config->nfs4_params,
399 : security_info_sent,
400 : psd,
401 : nfs4acl_smb4acl_set_fn);
402 0 : return status;
403 : }
404 :
405 212 : static int nfs4acl_connect(struct vfs_handle_struct *handle,
406 : const char *service,
407 : const char *user)
408 : {
409 : const struct loadparm_substitution *lp_sub =
410 212 : loadparm_s3_global_substitution();
411 212 : struct nfs4acl_config *config = NULL;
412 212 : const struct enum_list *default_acl_style_list = NULL;
413 212 : const char *default_xattr_name = NULL;
414 212 : bool default_validate_mode = true;
415 : int enumval;
416 : unsigned nfs_version;
417 : int ret;
418 :
419 212 : default_acl_style_list = get_default_acl_style_list();
420 :
421 212 : config = talloc_zero(handle->conn, struct nfs4acl_config);
422 212 : if (config == NULL) {
423 0 : DBG_ERR("talloc_zero() failed\n");
424 0 : return -1;
425 : }
426 :
427 212 : ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
428 212 : if (ret < 0) {
429 0 : TALLOC_FREE(config);
430 0 : return ret;
431 : }
432 :
433 212 : ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
434 212 : if (ret < 0) {
435 0 : TALLOC_FREE(config);
436 0 : return ret;
437 : }
438 :
439 212 : enumval = lp_parm_enum(SNUM(handle->conn),
440 : "nfs4acl_xattr",
441 : "encoding",
442 : nfs4acl_encoding,
443 : NFS4ACL_ENCODING_NDR);
444 212 : if (enumval == -1) {
445 0 : DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
446 0 : return -1;
447 : }
448 212 : config->encoding = (enum nfs4acl_encoding)enumval;
449 :
450 212 : switch (config->encoding) {
451 60 : case NFS4ACL_ENCODING_XDR:
452 60 : default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
453 60 : break;
454 60 : case NFS4ACL_ENCODING_NFS:
455 60 : default_xattr_name = NFS4ACL_NFS_XATTR_NAME;
456 60 : default_validate_mode = false;
457 60 : break;
458 92 : case NFS4ACL_ENCODING_NDR:
459 : default:
460 92 : default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
461 92 : break;
462 : }
463 :
464 212 : nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
465 : "nfs4acl_xattr",
466 : "version",
467 : 41);
468 212 : switch (nfs_version) {
469 122 : case 40:
470 122 : config->nfs_version = ACL4_XATTR_VERSION_40;
471 122 : break;
472 90 : case 41:
473 90 : config->nfs_version = ACL4_XATTR_VERSION_41;
474 90 : break;
475 0 : default:
476 0 : config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
477 0 : break;
478 : }
479 :
480 212 : config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
481 : "nfs4acl_xattr",
482 : "default acl style",
483 : default_acl_style_list,
484 : DEFAULT_ACL_EVERYONE);
485 :
486 212 : config->xattr_name = lp_parm_substituted_string(config, lp_sub,
487 212 : SNUM(handle->conn),
488 : "nfs4acl_xattr",
489 : "xattr_name",
490 : default_xattr_name);
491 :
492 212 : config->nfs4_id_numeric = lp_parm_bool(SNUM(handle->conn),
493 : "nfs4acl_xattr",
494 : "nfs4_id_numeric",
495 : false);
496 :
497 :
498 212 : config->validate_mode = lp_parm_bool(SNUM(handle->conn),
499 : "nfs4acl_xattr",
500 : "validate_mode",
501 : default_validate_mode);
502 :
503 212 : SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
504 : return -1);
505 :
506 : /*
507 : * Ensure we have the parameters correct if we're using this module.
508 : */
509 212 : DBG_NOTICE("Setting 'inherit acls = true', "
510 : "'dos filemode = true', "
511 : "'force unknown acl user = true', "
512 : "'create mask = 0666', "
513 : "'directory mask = 0777' and "
514 : "'store dos attributes = yes' "
515 : "for service [%s]\n", service);
516 :
517 212 : lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
518 212 : lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
519 212 : lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
520 212 : lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
521 212 : lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
522 212 : lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
523 :
524 212 : return 0;
525 : }
526 :
527 : /*
528 : As long as Samba does not support an exiplicit method for a module
529 : to define conflicting vfs methods, we should override all conflicting
530 : methods here. That way, we know we are using the NFSv4 storage
531 :
532 : Function declarations taken from vfs_solarisacl
533 : */
534 :
535 1134 : static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
536 : files_struct *fsp,
537 : SMB_ACL_TYPE_T type,
538 : TALLOC_CTX *mem_ctx)
539 : {
540 1134 : return (SMB_ACL_T)NULL;
541 : }
542 :
543 0 : static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
544 : files_struct *fsp,
545 : SMB_ACL_TYPE_T type,
546 : SMB_ACL_T theacl)
547 : {
548 0 : return -1;
549 : }
550 :
551 0 : static int nfs4acl_xattr_fail__sys_acl_delete_def_fd(vfs_handle_struct *handle,
552 : files_struct *fsp)
553 : {
554 0 : return -1;
555 : }
556 :
557 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)
558 : {
559 0 : return -1;
560 : }
561 :
562 : /* VFS operations structure */
563 :
564 : static struct vfs_fn_pointers nfs4acl_xattr_fns = {
565 : .connect_fn = nfs4acl_connect,
566 : .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
567 : .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
568 :
569 : .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
570 : .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
571 : .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
572 : .sys_acl_delete_def_fd_fn = nfs4acl_xattr_fail__sys_acl_delete_def_fd,
573 : };
574 :
575 : static_decl_vfs;
576 203 : NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
577 : {
578 203 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
579 : &nfs4acl_xattr_fns);
580 : }
|