vfs_nfs4acl_xattr: move the meat of the implementation to a seperate file
[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                                             40);
354         switch (nfs_version) {
355         case 40:
356                 config->nfs_version = ACL4_XATTR_VERSION_40;
357                 break;
358         default:
359                 config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
360                 break;
361         }
362
363         config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
364                                                  "nfs4acl_xattr",
365                                                  "default acl style",
366                                                  default_acl_style_list,
367                                                  DEFAULT_ACL_EVERYONE);
368
369         config->xattr_name = lp_parm_talloc_string(config,
370                                                    SNUM(handle->conn),
371                                                    "nfs4acl_xattr",
372                                                    "xattr_name",
373                                                    default_xattr_name);
374
375         SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
376                                 return -1);
377
378         /*
379          * Ensure we have the parameters correct if we're using this module.
380          */
381         DBG_NOTICE("Setting 'inherit acls = true', "
382                    "'dos filemode = true', "
383                    "'force unknown acl user = true', "
384                    "'create mask = 0666', "
385                    "'directory mask = 0777' and "
386                    "'store dos attributes = yes' "
387                    "for service [%s]\n", service);
388
389         lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
390         lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
391         lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
392         lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
393         lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
394         lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
395
396         return 0;
397 }
398
399 /*
400    As long as Samba does not support an exiplicit method for a module
401    to define conflicting vfs methods, we should override all conflicting
402    methods here.  That way, we know we are using the NFSv4 storage
403
404    Function declarations taken from vfs_solarisacl
405 */
406
407 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
408                                         const struct smb_filename *smb_fname,
409                                         SMB_ACL_TYPE_T type,
410                                         TALLOC_CTX *mem_ctx)
411 {
412         return (SMB_ACL_T)NULL;
413 }
414
415 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
416                                                     files_struct *fsp,
417                                                     TALLOC_CTX *mem_ctx)
418 {
419         return (SMB_ACL_T)NULL;
420 }
421
422 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
423                                          const struct smb_filename *smb_fname,
424                                          SMB_ACL_TYPE_T type,
425                                          SMB_ACL_T theacl)
426 {
427         return -1;
428 }
429
430 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
431                                        files_struct *fsp,
432                                        SMB_ACL_T theacl)
433 {
434         return -1;
435 }
436
437 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
438                         const struct smb_filename *smb_fname)
439 {
440         return -1;
441 }
442
443 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
444                         const struct smb_filename *smb_fname,
445                         TALLOC_CTX *mem_ctx,
446                         char **blob_description,
447                         DATA_BLOB *blob)
448 {
449         return -1;
450 }
451
452 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)
453 {
454         return -1;
455 }
456
457 /* VFS operations structure */
458
459 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
460         .connect_fn = nfs4acl_connect,
461         .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
462         .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
463         .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
464
465         .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
466         .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
467         .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
468         .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
469         .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
470         .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
471         .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
472 };
473
474 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *);
475 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
476 {
477         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
478                                 &nfs4acl_xattr_fns);
479 }