s3: VFS: Change SMB_VFS_GETXATTR to use const struct smb_filename * instead of const...
[kai/samba-autobuild/.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  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, see <http://www.gnu.org/licenses/>.
25  *
26  */
27
28 #include "includes.h"
29 #include "system/filesys.h"
30 #include "smbd/smbd.h"
31 #include "nfs4_acls.h"
32 #include "librpc/gen_ndr/ndr_nfs4acl.h"
33
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_VFS
36
37 static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
38 {
39         enum ndr_err_code ndr_err;
40         struct nfs4acl *acl = talloc(mem_ctx, struct nfs4acl);
41         if (!acl) {
42                 errno = ENOMEM;
43                 return NULL;
44         }
45
46         ndr_err = ndr_pull_struct_blob(blob, acl, acl,
47                 (ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
48
49         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
50                 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
51                           ndr_errstr(ndr_err)));
52                 TALLOC_FREE(acl);
53                 return NULL;
54         }
55         return acl;
56 }
57
58 static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
59 {
60         enum ndr_err_code ndr_err;
61         DATA_BLOB blob;
62         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
63                 (ndr_push_flags_fn_t)ndr_push_nfs4acl);
64
65         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
66                 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
67                           ndr_errstr(ndr_err)));
68                 return data_blob_null;
69         }
70         return blob;
71 }
72
73 static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
74                                          DATA_BLOB *blob,
75                                          struct SMB4ACL_T **ppacl)
76 {
77         int i;
78         struct nfs4acl *nfs4acl = NULL;
79         struct SMB4ACL_T *pacl = NULL;
80         TALLOC_CTX *frame = talloc_stackframe();
81         nfs4acl = nfs4acl_blob2acl(blob, frame);
82
83         /* create SMB4ACL data */
84         if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
85                 TALLOC_FREE(frame);
86                 return NT_STATUS_NO_MEMORY;
87         }
88         for(i=0; i<nfs4acl->a_count; i++) {
89                 SMB_ACE4PROP_T aceprop;
90
91                 aceprop.aceType  = (uint32_t) nfs4acl->ace[i].e_type;
92                 aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
93                 aceprop.aceMask  = (uint32_t) nfs4acl->ace[i].e_mask;
94                 aceprop.who.id   = (uint32_t) nfs4acl->ace[i].e_id;
95                 if (!strcmp(nfs4acl->ace[i].e_who,
96                             NFS4ACL_XATTR_OWNER_WHO)) {
97                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
98                         aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
99                 } else if (!strcmp(nfs4acl->ace[i].e_who,
100                                    NFS4ACL_XATTR_GROUP_WHO)) {
101                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
102                         aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
103                 } else if (!strcmp(nfs4acl->ace[i].e_who,
104                                    NFS4ACL_XATTR_EVERYONE_WHO)) {
105                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
106                         aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
107                 } else {
108                         aceprop.flags = 0;
109                 }
110                 if(smb_add_ace4(pacl, &aceprop) == NULL) {
111                         TALLOC_FREE(frame);
112                         return NT_STATUS_NO_MEMORY;
113                 }
114         }
115
116         *ppacl = pacl;
117         TALLOC_FREE(frame);
118         return NT_STATUS_OK;
119 }
120
121 /* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
122 static NTSTATUS nfs4_fget_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
123                                    files_struct *fsp, struct SMB4ACL_T **ppacl)
124 {
125         NTSTATUS status;
126         DATA_BLOB blob = data_blob_null;
127         ssize_t length;
128         TALLOC_CTX *frame = talloc_stackframe();
129
130         do {
131                 blob.length += 1000;
132                 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
133                 if (!blob.data) {
134                         TALLOC_FREE(frame);
135                         errno = ENOMEM;
136                         return NT_STATUS_NO_MEMORY;
137                 }
138                 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, NFS4ACL_XATTR_NAME, blob.data, blob.length);
139                 blob.length = length;
140         } while (length == -1 && errno == ERANGE);
141         if (length == -1) {
142                 TALLOC_FREE(frame);
143                 return map_nt_error_from_unix(errno);
144         }
145         status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl);
146         TALLOC_FREE(frame);
147         return status;
148 }
149
150 /* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
151 static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle,
152                                 TALLOC_CTX *mem_ctx,
153                                 const struct smb_filename *smb_fname,
154                                 struct SMB4ACL_T **ppacl)
155 {
156         NTSTATUS status;
157         DATA_BLOB blob = data_blob_null;
158         ssize_t length;
159         TALLOC_CTX *frame = talloc_stackframe();
160
161         do {
162                 blob.length += 1000;
163                 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
164                 if (!blob.data) {
165                         TALLOC_FREE(frame);
166                         errno = ENOMEM;
167                         return NT_STATUS_NO_MEMORY;
168                 }
169                 length = SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
170                                 NFS4ACL_XATTR_NAME, blob.data, blob.length);
171                 blob.length = length;
172         } while (length == -1 && errno == ERANGE);
173         if (length == -1) {
174                 TALLOC_FREE(frame);
175                 return map_nt_error_from_unix(errno);
176         }
177         status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl);
178         TALLOC_FREE(frame);
179         return status;
180 }
181
182 static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
183                                     struct SMB4ACL_T *smbacl,
184                                     struct nfs4acl **pnfs4acl,
185                                     bool denymissingspecial)
186 {
187         struct nfs4acl *nfs4acl;
188         struct SMB4ACE_T *smbace;
189         bool have_special_id = false;
190         int i;
191
192         /* allocate the field of NFS4 aces */
193         nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
194         if(nfs4acl == NULL) {
195                 errno = ENOMEM;
196                 return false;
197         }
198
199         nfs4acl->a_count = smb_get_naces(smbacl);
200
201         nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
202                                          nfs4acl->a_count);
203         if(nfs4acl->ace == NULL) {
204                 TALLOC_FREE(nfs4acl);
205                 errno = ENOMEM;
206                 return false;
207         }
208
209         /* handle all aces */
210         for(smbace = smb_first_ace4(smbacl), i = 0;
211                         smbace!=NULL;
212                         smbace = smb_next_ace4(smbace), i++) {
213                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
214
215                 nfs4acl->ace[i].e_type        = aceprop->aceType;
216                 nfs4acl->ace[i].e_flags       = aceprop->aceFlags;
217                 nfs4acl->ace[i].e_mask        = aceprop->aceMask;
218                 nfs4acl->ace[i].e_id          = aceprop->who.id;
219                 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
220                         switch(aceprop->who.special_id) {
221                         case SMB_ACE4_WHO_EVERYONE:
222                                 nfs4acl->ace[i].e_who =
223                                         NFS4ACL_XATTR_EVERYONE_WHO;
224                                 break;
225                         case SMB_ACE4_WHO_OWNER:
226                                 nfs4acl->ace[i].e_who =
227                                         NFS4ACL_XATTR_OWNER_WHO;
228                                 break;
229                         case SMB_ACE4_WHO_GROUP:
230                                 nfs4acl->ace[i].e_who =
231                                         NFS4ACL_XATTR_GROUP_WHO;
232                                 break;
233                         default:
234                                 DEBUG(8, ("unsupported special_id %d\n", \
235                                         aceprop->who.special_id));
236                                 continue; /* don't add it !!! */
237                         }
238                         have_special_id = true;
239                 } else {
240                         nfs4acl->ace[i].e_who = "";
241                 }
242         }
243
244         if (!have_special_id && denymissingspecial) {
245                 TALLOC_FREE(nfs4acl);
246                 errno = EACCES;
247                 return false;
248         }
249
250         SMB_ASSERT(i == nfs4acl->a_count);
251
252         *pnfs4acl = nfs4acl;
253         return true;
254 }
255
256 static bool nfs4acl_xattr_set_smb4acl(vfs_handle_struct *handle,
257                                       const struct smb_filename *smb_fname,
258                                       struct SMB4ACL_T *smbacl)
259 {
260         TALLOC_CTX *frame = talloc_stackframe();
261         struct nfs4acl *nfs4acl;
262         int ret;
263         bool denymissingspecial;
264         DATA_BLOB blob;
265
266         denymissingspecial = lp_parm_bool(handle->conn->params->service,
267                                           "nfs4acl_xattr",
268                                           "denymissingspecial", false);
269
270         if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
271                                      denymissingspecial)) {
272                 DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
273                 TALLOC_FREE(frame);
274                 return false;
275         }
276
277         blob = nfs4acl_acl2blob(frame, nfs4acl);
278         if (!blob.data) {
279                 DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
280                 TALLOC_FREE(frame);
281                 errno = EINVAL;
282                 return false;
283         }
284         ret = SMB_VFS_NEXT_SETXATTR(handle, smb_fname, NFS4ACL_XATTR_NAME,
285                                     blob.data, blob.length, 0);
286         if (ret != 0) {
287                 DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
288         }
289         TALLOC_FREE(frame);
290         return ret == 0;
291 }
292
293 /* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
294 static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
295                                        files_struct *fsp,
296                                        struct SMB4ACL_T *smbacl)
297 {
298         TALLOC_CTX *frame = talloc_stackframe();
299         struct nfs4acl *nfs4acl;
300         int ret;
301         bool denymissingspecial;
302         DATA_BLOB blob;
303
304         denymissingspecial = lp_parm_bool(fsp->conn->params->service,
305                                           "nfs4acl_xattr",
306                                           "denymissingspecial", false);
307
308         if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
309                                      denymissingspecial)) {
310                 DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
311                 TALLOC_FREE(frame);
312                 return false;
313         }
314
315         blob = nfs4acl_acl2blob(frame, nfs4acl);
316         if (!blob.data) {
317                 DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
318                 TALLOC_FREE(frame);
319                 errno = EINVAL;
320                 return false;
321         }
322         if (fsp->fh->fd == -1) {
323                 DEBUG(0, ("Error: fsp->fh->fd == -1\n"));
324         }
325         ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_XATTR_NAME,
326                                      blob.data, blob.length, 0);
327         if (ret != 0) {
328                 DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
329         }
330         TALLOC_FREE(frame);
331         return ret == 0;
332 }
333
334 /* nfs4_set_nt_acl()
335  * set the local file's acls obtaining it in NT form
336  * using the NFSv4 format conversion
337  */
338 static NTSTATUS nfs4_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
339                            uint32_t security_info_sent,
340                            const struct security_descriptor *psd)
341 {
342         return smb_set_nt_acl_nfs4(handle, fsp, NULL, security_info_sent, psd,
343                         nfs4acl_xattr_fset_smb4acl);
344 }
345
346 static struct SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
347 {
348         struct SMB4ACL_T *pacl = NULL;
349         struct SMB4ACE_T *pace;
350         SMB_ACE4PROP_T ace = {
351                 .flags = SMB_ACE4_ID_SPECIAL,
352                 .who = {
353                         .id = SMB_ACE4_WHO_EVERYONE,
354                 },
355                 .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE,
356                 .aceFlags = 0,
357                 .aceMask = SMB_ACE4_ALL_MASKS,
358         };
359
360         DEBUG(10, ("Building default full access acl\n"));
361
362         pacl = smb_create_smb4acl(mem_ctx);
363         if (pacl == NULL) {
364                 DEBUG(0, ("talloc failed\n"));
365                 errno = ENOMEM;
366                 return NULL;
367         }
368
369         pace = smb_add_ace4(pacl, &ace);
370         if (pace == NULL) {
371                 DEBUG(0, ("talloc failed\n"));
372                 TALLOC_FREE(pacl);
373                 errno = ENOMEM;
374                 return NULL;
375         }
376
377         return pacl;
378 }
379
380 /*
381  * Because there is no good way to guarantee that a new xattr will be
382  * created on file creation there might be no acl xattr on a file when
383  * trying to read the acl. In this case the acl xattr will get
384  * constructed at that time from the parent acl.
385  * If the parent ACL doesn't have an xattr either the call will
386  * recurse to the next parent directory until the share root is
387  * reached. If the share root doesn't contain an ACL xattr either a
388  * default ACL will be used.
389  * Also a default ACL will be set if a non inheriting ACL is encountered.
390  *
391  * Basic algorithm:
392  *   read acl xattr blob
393  *   if acl xattr blob doesn't exist
394  *     stat current directory to know if it's a file or directory
395  *     read acl xattr blob from parent dir
396  *     acl xattr blob to smb nfs4 acl
397  *     calculate inherited smb nfs4 acl
398  *     without inheritance use default smb nfs4 acl
399  *     smb nfs4 acl to acl xattr blob
400  *     set acl xattr blob
401  *     return smb nfs4 acl
402  *   else
403  *     acl xattr blob to smb nfs4 acl
404  *
405  * Todo: Really use mem_ctx after fixing interface of nfs4_acls
406  */
407 static struct SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
408         const struct smb_filename *smb_fname_in,
409         TALLOC_CTX *mem_ctx)
410 {
411         char *parent_dir = NULL;
412         struct SMB4ACL_T *pparentacl = NULL;
413         struct SMB4ACL_T *pchildacl = NULL;
414         struct SMB4ACE_T *pace;
415         SMB_ACE4PROP_T ace;
416         bool isdir;
417         struct smb_filename *smb_fname = NULL;
418         struct smb_filename *smb_fname_parent = NULL;
419         NTSTATUS status;
420         int ret;
421         TALLOC_CTX *frame = talloc_stackframe();
422
423         DEBUG(10, ("nfs4acls_inheritacl invoked for %s\n",
424                         smb_fname_in->base_name));
425         smb_fname = cp_smb_filename_nostream(frame, smb_fname_in);
426         if (smb_fname == NULL) {
427                 TALLOC_FREE(frame);
428                 errno = ENOMEM;
429                 return NULL;
430         }
431
432         ret = SMB_VFS_STAT(handle->conn, smb_fname);
433         if (ret == -1) {
434                 DEBUG(0,("nfs4acls_inheritacl: failed to stat "
435                          "directory %s. Error was %s\n",
436                          smb_fname_str_dbg(smb_fname),
437                          strerror(errno)));
438                 TALLOC_FREE(frame);
439                 return NULL;
440         }
441         isdir = S_ISDIR(smb_fname->st.st_ex_mode);
442
443         if (!parent_dirname(talloc_tos(),
444                             smb_fname->base_name,
445                             &parent_dir,
446                             NULL)) {
447                 TALLOC_FREE(frame);
448                 errno = ENOMEM;
449                 return NULL;
450         }
451
452         smb_fname_parent = synthetic_smb_fname(talloc_tos(),
453                                 parent_dir,
454                                 NULL,
455                                 NULL,
456                                 0);
457         if (smb_fname_parent == NULL) {
458                 TALLOC_FREE(frame);
459                 errno = ENOMEM;
460                 return NULL;
461         }
462
463         status = nfs4_get_nfs4_acl(handle, frame, smb_fname_parent,
464                                         &pparentacl);
465         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)
466             && strncmp(parent_dir, ".", 2) != 0) {
467                 pparentacl = nfs4acls_inheritacl(handle,
468                                                 smb_fname_parent,
469                                                 frame);
470         }
471         else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
472                 pparentacl = nfs4acls_defaultacl(frame);
473
474         }
475         else if (!NT_STATUS_IS_OK(status)) {
476                 TALLOC_FREE(frame);
477                 return NULL;
478         }
479
480         pchildacl = smb_create_smb4acl(mem_ctx);
481         if (pchildacl == NULL) {
482                 DEBUG(0, ("talloc failed\n"));
483                 TALLOC_FREE(frame);
484                 errno = ENOMEM;
485                 return NULL;
486         }
487
488         for (pace = smb_first_ace4(pparentacl); pace != NULL;
489              pace = smb_next_ace4(pace)) {
490                 struct SMB4ACE_T *pchildace;
491                 ace = *smb_get_ace4(pace);
492                 if ((isdir && !(ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) ||
493                     (!isdir && !(ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE))) {
494                         DEBUG(10, ("non inheriting ace type: %d, iflags: %x, "
495                                    "flags: %x, mask: %x, who: %d\n",
496                                    ace.aceType, ace.flags, ace.aceFlags,
497                                    ace.aceMask, ace.who.id));
498                         continue;
499                 }
500                 DEBUG(10, ("inheriting ace type: %d, iflags: %x, "
501                            "flags: %x, mask: %x, who: %d\n",
502                            ace.aceType, ace.flags, ace.aceFlags,
503                            ace.aceMask, ace.who.id));
504                 ace.aceFlags |= SMB_ACE4_INHERITED_ACE;
505                 if (ace.aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) {
506                         ace.aceFlags &= ~SMB_ACE4_INHERIT_ONLY_ACE;
507                 }
508                 if (ace.aceFlags & SMB_ACE4_NO_PROPAGATE_INHERIT_ACE) {
509                         ace.aceFlags &= ~SMB_ACE4_FILE_INHERIT_ACE;
510                         ace.aceFlags &= ~SMB_ACE4_DIRECTORY_INHERIT_ACE;
511                         ace.aceFlags &= ~SMB_ACE4_NO_PROPAGATE_INHERIT_ACE;
512                 }
513                 pchildace = smb_add_ace4(pchildacl, &ace);
514                 if (pchildace == NULL) {
515                         DEBUG(0, ("talloc failed\n"));
516                         TALLOC_FREE(frame);
517                         errno = ENOMEM;
518                         return NULL;
519                 }
520         }
521
522         /* Set a default ACL if we didn't inherit anything. */
523         if (smb_first_ace4(pchildacl) == NULL) {
524                 TALLOC_FREE(pchildacl);
525                 pchildacl = nfs4acls_defaultacl(mem_ctx);
526         }
527
528         /* store the returned ACL to get it directly in the
529            future and avoid dynamic inheritance behavior. */
530         nfs4acl_xattr_set_smb4acl(handle, smb_fname, pchildacl);
531
532         TALLOC_FREE(frame);
533         return pchildacl;
534 }
535
536 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
537                                    struct files_struct *fsp,
538                                    uint32_t security_info,
539                                    TALLOC_CTX *mem_ctx,
540                                    struct security_descriptor **ppdesc)
541 {
542         struct SMB4ACL_T *pacl;
543         NTSTATUS status;
544         TALLOC_CTX *frame = talloc_stackframe();
545
546         status = nfs4_fget_nfs4_acl(handle, frame, fsp, &pacl);
547         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
548                 pacl = nfs4acls_inheritacl(handle, fsp->fsp_name,
549                                            frame);
550         }
551         else if (!NT_STATUS_IS_OK(status)) {
552                 TALLOC_FREE(frame);
553                 return status;
554         }
555
556         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
557                                       ppdesc, pacl);
558         TALLOC_FREE(frame);
559         return status;
560 }
561
562 static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
563                                   const struct smb_filename *smb_fname,
564                                   uint32_t security_info,
565                                   TALLOC_CTX *mem_ctx,
566                                   struct security_descriptor **ppdesc)
567 {
568         struct SMB4ACL_T *pacl;
569         NTSTATUS status;
570         TALLOC_CTX *frame = talloc_stackframe();
571
572         status = nfs4_get_nfs4_acl(handle, frame, smb_fname, &pacl);
573         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
574                 pacl = nfs4acls_inheritacl(handle, smb_fname, frame);
575         }
576         else if (!NT_STATUS_IS_OK(status)) {
577                 TALLOC_FREE(frame);
578                 return status;
579         }
580
581         status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
582                                      security_info, mem_ctx, ppdesc,
583                                      pacl);
584         TALLOC_FREE(frame);
585         return status;
586 }
587
588 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
589                          files_struct *fsp,
590                          uint32_t security_info_sent,
591                          const struct security_descriptor *psd)
592 {
593         return nfs4_set_nt_acl(handle, fsp, security_info_sent, psd);
594 }
595
596 /*
597    As long as Samba does not support an exiplicit method for a module
598    to define conflicting vfs methods, we should override all conflicting
599    methods here.  That way, we know we are using the NFSv4 storage
600
601    Function declarations taken from vfs_solarisacl
602 */
603
604 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
605                                         const struct smb_filename *smb_fname,
606                                         SMB_ACL_TYPE_T type,
607                                         TALLOC_CTX *mem_ctx)
608 {
609         return (SMB_ACL_T)NULL;
610 }
611
612 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
613                                                     files_struct *fsp,
614                                                     TALLOC_CTX *mem_ctx)
615 {
616         return (SMB_ACL_T)NULL;
617 }
618
619 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
620                                          const struct smb_filename *smb_fname,
621                                          SMB_ACL_TYPE_T type,
622                                          SMB_ACL_T theacl)
623 {
624         return -1;
625 }
626
627 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
628                                        files_struct *fsp,
629                                        SMB_ACL_T theacl)
630 {
631         return -1;
632 }
633
634 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
635                         const struct smb_filename *smb_fname)
636 {
637         return -1;
638 }
639
640 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
641                         const struct smb_filename *smb_fname,
642                         TALLOC_CTX *mem_ctx,
643                         char **blob_description,
644                         DATA_BLOB *blob)
645 {
646         return -1;
647 }
648
649 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)
650 {
651         return -1;
652 }
653
654 /* VFS operations structure */
655
656 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
657         .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
658         .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
659         .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
660         .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
661         .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
662         .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
663         .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
664         .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
665         .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
666         .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
667 };
668
669 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *);
670 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
671 {
672         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
673                                 &nfs4acl_xattr_fns);
674 }