s3:modules: Remove unreachable code (CID 1508998)
[samba.git] / source3 / modules / vfs_nfs4acl_xattr.c
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 static bool nfs4acl_validate_blob(vfs_handle_struct *handle,
55                                   files_struct *fsp)
56 {
57         struct nfs4acl_config *config = NULL;
58         mode_t expected_mode;
59         int ret;
60
61         SMB_VFS_HANDLE_GET_DATA(handle, config,
62                                 struct nfs4acl_config,
63                                 return false);
64
65         if (!config->validate_mode) {
66                 return true;
67         }
68
69         if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
70                 expected_mode = 0777;
71         } else {
72                 expected_mode = 0666;
73         }
74         if ((fsp->fsp_name->st.st_ex_mode & expected_mode) == expected_mode) {
75                 return true;
76         }
77
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;
84         }
85
86         return true;
87 }
88
89 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         struct nfs4acl_config *config = NULL;
95         size_t allocsize = 256;
96         ssize_t length;
97         bool ok;
98
99         SMB_VFS_HANDLE_GET_DATA(handle, config,
100                                 struct nfs4acl_config,
101                                 return NT_STATUS_INTERNAL_ERROR);
102
103         *blob = data_blob_null;
104
105         ok = nfs4acl_validate_blob(handle, fsp);
106         if (!ok) {
107                 return NT_STATUS_INTERNAL_ERROR;
108         }
109
110         do {
111
112                 allocsize *= 4;
113                 ok = data_blob_realloc(mem_ctx, blob, allocsize);
114                 if (!ok) {
115                         return NT_STATUS_NO_MEMORY;
116                 }
117
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);
124
125         if (length == -1) {
126                 return map_nt_error_from_unix(errno);
127         }
128
129         return NT_STATUS_OK;
130 }
131
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)
137 {
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;
143
144         SMB_VFS_HANDLE_GET_DATA(handle, config,
145                                 struct nfs4acl_config,
146                                 return NT_STATUS_INTERNAL_ERROR);
147
148         default_acl_style = config->default_acl_style;
149
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);
156                 }
157         }
158
159         if (S_ISDIR(sbuf.st_ex_mode)) {
160                 required_mode = 0777;
161         } else {
162                 required_mode = 0666;
163         }
164         if ((sbuf.st_ex_mode & required_mode) != required_mode) {
165                 default_acl_style = DEFAULT_ACL_POSIX;
166         }
167
168         return make_default_filesystem_acl(mem_ctx,
169                                            default_acl_style,
170                                            smb_fname->base_name,
171                                            &sbuf,
172                                            sd);
173 }
174
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)
179 {
180         struct nfs4acl_config *config = NULL;
181         NTSTATUS status;
182
183         SMB_VFS_HANDLE_GET_DATA(handle, config,
184                                 struct nfs4acl_config,
185                                 return NT_STATUS_INTERNAL_ERROR);
186
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;
200         }
201
202         return status;
203 }
204
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)
210 {
211         struct SMB4ACL_T *smb4acl = NULL;
212         TALLOC_CTX *frame = talloc_stackframe();
213         DATA_BLOB blob;
214         NTSTATUS status;
215
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);
221         }
222         if (!NT_STATUS_IS_OK(status)) {
223                 TALLOC_FREE(frame);
224                 return status;
225         }
226
227         status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
228         if (!NT_STATUS_IS_OK(status)) {
229                 TALLOC_FREE(frame);
230                 return status;
231         }
232
233         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
234                                       sd, smb4acl);
235         TALLOC_FREE(frame);
236         return status;
237 }
238
239 static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
240                                    files_struct *fsp,
241                                    struct SMB4ACL_T *smb4acl)
242 {
243         struct nfs4acl_config *config = NULL;
244         DATA_BLOB blob;
245         NTSTATUS status;
246         int saved_errno = 0;
247         int ret;
248
249         SMB_VFS_HANDLE_GET_DATA(handle, config,
250                                 struct nfs4acl_config,
251                                 return false);
252
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;
269         }
270         if (!NT_STATUS_IS_OK(status)) {
271                 return false;
272         }
273
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;
278         }
279         data_blob_free(&blob);
280         if (saved_errno != 0) {
281                 errno = saved_errno;
282         }
283         if (ret != 0) {
284                 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
285                 return false;
286         }
287
288         return true;
289 }
290
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)
295 {
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;
305
306         SMB_VFS_HANDLE_GET_DATA(handle, config,
307                                 struct nfs4acl_config,
308                                 return NT_STATUS_INTERNAL_ERROR);
309
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;
313         }
314
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;
320         }
321         if (!config->validate_mode) {
322                 existing_mode = 0;
323                 expected_mode = 0;
324         }
325         if ((existing_mode & expected_mode) != expected_mode) {
326
327                 restored_mode = existing_mode | expected_mode;
328
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);
337                 }
338         }
339
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;
348         }
349         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
350                 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         if ((security_info_sent & SECINFO_OWNER) &&
360             (psd->owner_sid != NULL))
361         {
362                 chown_needed = true;
363         }
364         if ((security_info_sent & SECINFO_GROUP) &&
365             (psd->group_sid != NULL))
366         {
367                 chown_needed = true;
368         }
369
370         if (get_current_uid(handle->conn) == 0 ||
371             chown_needed == false ||
372             !(fsp->access_mask & SEC_STD_WRITE_OWNER))
373         {
374                 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         token = get_current_nttok(fsp->conn);
385         if (!security_token_is_sid(token, psd->owner_sid)) {
386                 return NT_STATUS_INVALID_OWNER;
387         }
388
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));
392
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;
400 }
401
402 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                 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;
415
416         default_acl_style_list = get_default_acl_style_list();
417
418         config = talloc_zero(handle->conn, struct nfs4acl_config);
419         if (config == NULL) {
420                 DBG_ERR("talloc_zero() failed\n");
421                 return -1;
422         }
423
424         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
425         if (ret < 0) {
426                 TALLOC_FREE(config);
427                 return ret;
428         }
429
430         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
431         if (ret < 0) {
432                 TALLOC_FREE(config);
433                 return ret;
434         }
435
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;
444         }
445         config->encoding = (enum nfs4acl_encoding)enumval;
446
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;
459         }
460
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;
475         }
476
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);
482
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);
488
489         config->nfs4_id_numeric = lp_parm_bool(SNUM(handle->conn),
490                                                "nfs4acl_xattr",
491                                                "nfs4_id_numeric",
492                                                false);
493
494
495         config->validate_mode = lp_parm_bool(SNUM(handle->conn),
496                                              "nfs4acl_xattr",
497                                              "validate_mode",
498                                              default_validate_mode);
499
500         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         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         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");
520
521         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 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         return (SMB_ACL_T)NULL;
538 }
539
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)
544 {
545         return -1;
546 }
547
548 static int nfs4acl_xattr_fail__sys_acl_delete_def_fd(vfs_handle_struct *handle,
549                         files_struct *fsp)
550 {
551         return -1;
552 }
553
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)
555 {
556         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 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
574 {
575         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
576                                 &nfs4acl_xattr_fns);
577 }