31b85aea13f312d2f20d1aeabab51e6153f7d968
[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 "nfs4_acls.h"
33 #include "librpc/gen_ndr/ndr_nfs4acl.h"
34 #include "nfs4acl_xattr.h"
35 #include "nfs4acl_xattr_ndr.h"
36
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_VFS
39
40 static const struct enum_list nfs4acl_encoding[] = {
41         {NFS4ACL_ENCODING_NDR, "ndr"},
42         {NFS4ACL_ENCODING_XDR, "xdr"},
43 };
44
45 static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
46                                  files_struct *fsp,
47                                  const struct smb_filename *smb_fname_in,
48                                  TALLOC_CTX *mem_ctx,
49                                  DATA_BLOB *blob)
50 {
51         struct nfs4acl_config *config = NULL;
52         const struct smb_filename *smb_fname = NULL;
53         size_t allocsize = 256;
54         ssize_t length;
55         bool ok;
56
57         SMB_VFS_HANDLE_GET_DATA(handle, config,
58                                 struct nfs4acl_config,
59                                 return NT_STATUS_INTERNAL_ERROR);
60
61         *blob = data_blob_null;
62
63         if (fsp == NULL && smb_fname_in == NULL) {
64                 return NT_STATUS_INTERNAL_ERROR;
65         }
66         smb_fname = smb_fname_in;
67         if (smb_fname == NULL) {
68                 smb_fname = fsp->fsp_name;
69         }
70         if (smb_fname == NULL) {
71                 return NT_STATUS_INTERNAL_ERROR;
72         }
73
74         do {
75                 allocsize *= 4;
76                 ok = data_blob_realloc(mem_ctx, blob, allocsize);
77                 if (!ok) {
78                         return NT_STATUS_NO_MEMORY;
79                 }
80
81                 if (fsp != NULL && fsp->fh->fd != -1) {
82                         length = SMB_VFS_NEXT_FGETXATTR(handle,
83                                                         fsp,
84                                                         config->xattr_name,
85                                                         blob->data,
86                                                         blob->length);
87                 } else {
88                         length = SMB_VFS_NEXT_GETXATTR(handle,
89                                                        smb_fname,
90                                                        config->xattr_name,
91                                                        blob->data,
92                                                        blob->length);
93                 }
94         } while (length == -1 && errno == ERANGE && allocsize <= 65536);
95
96         if (length == -1) {
97                 return map_nt_error_from_unix(errno);
98         }
99
100         return NT_STATUS_OK;
101 }
102
103 static NTSTATUS nfs4acl_xattr_default_sd(
104         struct vfs_handle_struct *handle,
105         const struct smb_filename *smb_fname,
106         TALLOC_CTX *mem_ctx,
107         struct security_descriptor **sd)
108 {
109         struct nfs4acl_config *config = NULL;
110         enum default_acl_style default_acl_style;
111         mode_t required_mode;
112         SMB_STRUCT_STAT sbuf = smb_fname->st;
113         int ret;
114
115         SMB_VFS_HANDLE_GET_DATA(handle, config,
116                                 struct nfs4acl_config,
117                                 return NT_STATUS_INTERNAL_ERROR);
118
119         default_acl_style = config->default_acl_style;
120
121         if (!VALID_STAT(sbuf)) {
122                 ret = vfs_stat_smb_basename(handle->conn,
123                                             smb_fname,
124                                             &sbuf);
125                 if (ret != 0) {
126                         return map_nt_error_from_unix(errno);
127                 }
128         }
129
130         if (S_ISDIR(sbuf.st_ex_mode)) {
131                 required_mode = 0777;
132         } else {
133                 required_mode = 0666;
134         }
135         if ((sbuf.st_ex_mode & required_mode) != required_mode) {
136                 default_acl_style = DEFAULT_ACL_POSIX;
137         }
138
139         return make_default_filesystem_acl(mem_ctx,
140                                            default_acl_style,
141                                            smb_fname->base_name,
142                                            &sbuf,
143                                            sd);
144 }
145
146 static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
147                                      DATA_BLOB *blob,
148                                      TALLOC_CTX *mem_ctx,
149                                      struct SMB4ACL_T **smb4acl)
150 {
151         struct nfs4acl_config *config = NULL;
152         NTSTATUS status;
153
154         SMB_VFS_HANDLE_GET_DATA(handle, config,
155                                 struct nfs4acl_config,
156                                 return NT_STATUS_INTERNAL_ERROR);
157
158         switch (config->encoding) {
159         case NFS4ACL_ENCODING_NDR:
160                 status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
161                 break;
162         default:
163                 status = NT_STATUS_INTERNAL_ERROR;
164                 break;
165         }
166
167         return status;
168 }
169
170 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
171                                    struct files_struct *fsp,
172                                    uint32_t security_info,
173                                    TALLOC_CTX *mem_ctx,
174                                    struct security_descriptor **sd)
175 {
176         struct SMB4ACL_T *smb4acl = NULL;
177         TALLOC_CTX *frame = talloc_stackframe();
178         DATA_BLOB blob;
179         NTSTATUS status;
180
181         status = nfs4acl_get_blob(handle, fsp, NULL, frame, &blob);
182         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
183                 TALLOC_FREE(frame);
184                 return nfs4acl_xattr_default_sd(
185                         handle, fsp->fsp_name, mem_ctx, sd);
186         }
187         if (!NT_STATUS_IS_OK(status)) {
188                 TALLOC_FREE(frame);
189                 return status;
190         }
191
192         status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
193         if (!NT_STATUS_IS_OK(status)) {
194                 TALLOC_FREE(frame);
195                 return status;
196         }
197
198         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
199                                       sd, smb4acl);
200         TALLOC_FREE(frame);
201         return status;
202 }
203
204 static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
205                                   const struct smb_filename *smb_fname,
206                                   uint32_t security_info,
207                                   TALLOC_CTX *mem_ctx,
208                                   struct security_descriptor **sd)
209 {
210         struct SMB4ACL_T *smb4acl = NULL;
211         TALLOC_CTX *frame = talloc_stackframe();
212         DATA_BLOB blob;
213         NTSTATUS status;
214
215         status = nfs4acl_get_blob(handle, NULL, smb_fname, frame, &blob);
216         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
217                 TALLOC_FREE(frame);
218                 return nfs4acl_xattr_default_sd(
219                         handle, smb_fname, mem_ctx, sd);
220         }
221         if (!NT_STATUS_IS_OK(status)) {
222                 TALLOC_FREE(frame);
223                 return status;
224         }
225
226         status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
227         if (!NT_STATUS_IS_OK(status)) {
228                 TALLOC_FREE(frame);
229                 return status;
230         }
231
232         status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
233                                      security_info, mem_ctx, sd,
234                                      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 ret;
247
248         SMB_VFS_HANDLE_GET_DATA(handle, config,
249                                 struct nfs4acl_config,
250                                 return false);
251
252         switch (config->encoding) {
253         case NFS4ACL_ENCODING_NDR:
254                 status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
255                                                      smb4acl, &blob);
256                 break;
257         default:
258                 status = NT_STATUS_INTERNAL_ERROR;
259                 break;
260         }
261         if (!NT_STATUS_IS_OK(status)) {
262                 return false;
263         }
264
265         if (fsp->fh->fd != -1) {
266                 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
267                                              blob.data, blob.length, 0);
268         } else {
269                 ret = SMB_VFS_NEXT_SETXATTR(handle, fsp->fsp_name,
270                                             config->xattr_name,
271                                             blob.data, blob.length, 0);
272         }
273         data_blob_free(&blob);
274         if (ret != 0) {
275                 DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
276                 return false;
277         }
278
279         return true;
280 }
281
282 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
283                          files_struct *fsp,
284                          uint32_t security_info_sent,
285                          const struct security_descriptor *psd)
286 {
287         struct nfs4acl_config *config = NULL;
288
289         SMB_VFS_HANDLE_GET_DATA(handle, config,
290                                 struct nfs4acl_config,
291                                 return NT_STATUS_INTERNAL_ERROR);
292
293         return smb_set_nt_acl_nfs4(handle,
294                                    fsp,
295                                    &config->nfs4_params,
296                                    security_info_sent,
297                                    psd,
298                                    nfs4acl_smb4acl_set_fn);
299 }
300
301 static int nfs4acl_connect(struct vfs_handle_struct *handle,
302                            const char *service,
303                            const char *user)
304 {
305         struct nfs4acl_config *config = NULL;
306         const struct enum_list *default_acl_style_list = NULL;
307         const char *default_xattr_name = NULL;
308         int enumval;
309         unsigned nfs_version;
310         int ret;
311
312         default_acl_style_list = get_default_acl_style_list();
313
314         config = talloc_zero(handle->conn, struct nfs4acl_config);
315         if (config == NULL) {
316                 DBG_ERR("talloc_zero() failed\n");
317                 return -1;
318         }
319
320         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
321         if (ret < 0) {
322                 TALLOC_FREE(config);
323                 return ret;
324         }
325
326         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
327         if (ret < 0) {
328                 TALLOC_FREE(config);
329                 return ret;
330         }
331
332         enumval = lp_parm_enum(SNUM(handle->conn),
333                                "nfs4acl_xattr",
334                                "encoding",
335                                nfs4acl_encoding,
336                                NFS4ACL_ENCODING_NDR);
337         if (enumval == -1) {
338                 DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
339                 return -1;
340         }
341         config->encoding = (enum nfs4acl_encoding)enumval;
342
343         switch (config->encoding) {
344         case NFS4ACL_ENCODING_NDR:
345         default:
346                 default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
347                 break;
348         }
349
350         nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
351                                             "nfs4acl_xattr",
352                                             "version",
353                                             41);
354         switch (nfs_version) {
355         case 40:
356                 config->nfs_version = ACL4_XATTR_VERSION_40;
357                 break;
358         case 41:
359                 config->nfs_version = ACL4_XATTR_VERSION_41;
360                 break;
361         default:
362                 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
363                 break;
364         }
365
366         config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
367                                                  "nfs4acl_xattr",
368                                                  "default acl style",
369                                                  default_acl_style_list,
370                                                  DEFAULT_ACL_EVERYONE);
371
372         config->xattr_name = lp_parm_talloc_string(config,
373                                                    SNUM(handle->conn),
374                                                    "nfs4acl_xattr",
375                                                    "xattr_name",
376                                                    default_xattr_name);
377
378         SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
379                                 return -1);
380
381         /*
382          * Ensure we have the parameters correct if we're using this module.
383          */
384         DBG_NOTICE("Setting 'inherit acls = true', "
385                    "'dos filemode = true', "
386                    "'force unknown acl user = true', "
387                    "'create mask = 0666', "
388                    "'directory mask = 0777' and "
389                    "'store dos attributes = yes' "
390                    "for service [%s]\n", service);
391
392         lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
393         lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
394         lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
395         lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
396         lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
397         lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
398
399         return 0;
400 }
401
402 /*
403    As long as Samba does not support an exiplicit method for a module
404    to define conflicting vfs methods, we should override all conflicting
405    methods here.  That way, we know we are using the NFSv4 storage
406
407    Function declarations taken from vfs_solarisacl
408 */
409
410 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
411                                         const struct smb_filename *smb_fname,
412                                         SMB_ACL_TYPE_T type,
413                                         TALLOC_CTX *mem_ctx)
414 {
415         return (SMB_ACL_T)NULL;
416 }
417
418 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
419                                                     files_struct *fsp,
420                                                     TALLOC_CTX *mem_ctx)
421 {
422         return (SMB_ACL_T)NULL;
423 }
424
425 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
426                                          const struct smb_filename *smb_fname,
427                                          SMB_ACL_TYPE_T type,
428                                          SMB_ACL_T theacl)
429 {
430         return -1;
431 }
432
433 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
434                                        files_struct *fsp,
435                                        SMB_ACL_T theacl)
436 {
437         return -1;
438 }
439
440 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
441                         const struct smb_filename *smb_fname)
442 {
443         return -1;
444 }
445
446 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
447                         const struct smb_filename *smb_fname,
448                         TALLOC_CTX *mem_ctx,
449                         char **blob_description,
450                         DATA_BLOB *blob)
451 {
452         return -1;
453 }
454
455 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)
456 {
457         return -1;
458 }
459
460 /* VFS operations structure */
461
462 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
463         .connect_fn = nfs4acl_connect,
464         .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
465         .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
466         .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
467
468         .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
469         .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
470         .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
471         .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
472         .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
473         .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
474         .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
475 };
476
477 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *);
478 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
479 {
480         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
481                                 &nfs4acl_xattr_fns);
482 }