VFS: Remove SMB_VFS_LISTXATTR, no longer used
[samba.git] / source3 / modules / vfs_vxfs.c
1 /*
2 Unix SMB/CIFS implementation.
3 Wrap VxFS calls in vfs functions.
4 This module is for ACL and XATTR handling.
5
6 Copyright (C) Symantec Corporation <www.symantec.com> 2014
7 Copyright (C) Veritas Technologies LLC <www.veritas.com> 2016
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "smbd/smbd.h"
25 #include "librpc/gen_ndr/ndr_xattr.h"
26 #include "../libcli/security/security.h"
27 #include "../librpc/gen_ndr/ndr_security.h"
28 #include "system/filesys.h"
29 #include "vfs_vxfs.h"
30
31 #undef strcasecmp
32
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_VFS
35
36 #define MODULE_NAME "vxfs"
37
38 /*
39  * WARNING !! WARNING !!
40  *
41  * DO NOT CHANGE THIS FROM "system." space to
42  * "user." space unless you are shipping a product
43  * that RESTRICTS access to extended attributes
44  * to smbd-only. "system." space is restricted
45  * to root access only, "user." space is available
46  * to ANY USER.
47  *
48  * If this is changed to "user." and access
49  * to extended attributes is available via
50  * local processes or other remote file system
51  * (e.g. NFS) then the security of the system
52  * WILL BE COMPROMISED. i.e. non-root users
53  * WILL be able to overwrite Samba ACLs on
54  * the file system.
55  *
56  * If you need to modify this define, do
57  * so using CFLAGS on your build command
58  * line.
59  * e.g. CFLAGS=-DXATTR_USER_NTACL="user.NTACL"
60  *
61  * Added by: <jra@samba.org> 17 Sept. 2014.
62  *
63  */
64
65 #ifndef XATTR_USER_NTACL
66 #define XATTR_USER_NTACL "system.NTACL"
67 #endif
68
69 /* type values */
70 #define VXFS_ACL_UNDEFINED_TYPE  0
71 #define VXFS_ACL_USER_OBJ        1
72 #define VXFS_ACL_GROUP_OBJ       2
73 #define VXFS_ACL_USER            3
74 #define VXFS_ACL_GROUP           4
75 #define VXFS_ACL_OTHER           5
76 #define VXFS_ACL_MASK            6
77
78
79 /*
80  * Compare aces
81  * This will compare two ace entries for sorting
82  * each entry contains: type, perms and id
83  * Sort by type first, if type is same sort by id.
84  */
85 static int vxfs_ace_cmp(const void *ace1, const void *ace2)
86 {
87         int ret = 0;
88         uint16_t type_a1, type_a2;
89         uint32_t id_a1, id_a2;
90
91         /* Type must be compared first */
92         type_a1 = SVAL(ace1, 0);
93         type_a2 = SVAL(ace2, 0);
94
95         ret = (type_a1 - type_a2);
96         if (!ret) {
97                 /* Compare ID under type */
98                 /* skip perm thus take offset as 4*/
99                 id_a1 = IVAL(ace1, 4);
100                 id_a2 = IVAL(ace2, 4);
101                 ret = id_a1 - id_a2;
102         }
103
104         return ret;
105 }
106
107 static void vxfs_print_ace_buf(char *buf, int count) {
108
109         int i, offset = 0;
110         uint16_t type, perm;
111         uint32_t id;
112
113         DEBUG(10, ("vfs_vxfs: Printing aces:\n"));
114         for (i = 0; i < count; i++) {
115                 type = SVAL(buf, offset);
116                 offset += 2;
117                 perm = SVAL(buf, offset);
118                 offset += 2;
119                 id = IVAL(buf, offset);
120                 offset += 4;
121
122                 DEBUG(10, ("vfs_vxfs: type = %u, perm = %u, id = %u\n",
123                           (unsigned int)type, (unsigned int)perm,
124                           (unsigned int)id));
125         }
126 }
127
128 /*
129  * Sort aces so that comparing 2 ACLs will be straight forward.
130  * This function will fill buffer as follows:
131  * For each ace:
132  *      1. ace->a_type will be filled as first 2 bytes in buf.
133  *      2. ace->a_perm will be filled as next 2 bytes.
134  *      3. ace->xid will be filled as next 4 bytes.
135  * Thus each ace entry in buf is equal to 8 bytes.
136  * Also a_type is mapped to VXFS_ACL_* so that ordering aces
137  * becomes easy.
138  */
139 static char * vxfs_sort_acl(SMB_ACL_T theacl, TALLOC_CTX *mem_ctx,
140                             uint32_t o_uid,
141                             uint32_t o_gid) {
142
143         struct smb_acl_entry *smb_ace;
144         int i, count;
145         uint16_t type, perm;
146         uint32_t id;
147         int offset = 0;
148         char *buf = NULL;
149
150         count = theacl->count;
151
152         buf = talloc_zero_size(mem_ctx, count * 8);
153         if (!buf) {
154                 return NULL;
155         }
156
157         smb_ace = theacl->acl;
158
159         for (i = 0; i < count; i++) {
160                 /* Calculate type */
161                 /* Map type to SMB_ACL_* to VXFS_ACL_* */
162                 switch(smb_ace->a_type) {
163                 case SMB_ACL_USER:
164                         type = VXFS_ACL_USER;
165                         break;
166                 case SMB_ACL_USER_OBJ:
167                         type = VXFS_ACL_USER_OBJ;
168                         break;
169                 case SMB_ACL_GROUP:
170                         type = VXFS_ACL_GROUP;
171                         break;
172                 case SMB_ACL_GROUP_OBJ:
173                         type = VXFS_ACL_GROUP_OBJ;
174                         break;
175                 case SMB_ACL_OTHER:
176                         type = VXFS_ACL_OTHER;
177                         break;
178                 case SMB_ACL_MASK:
179                         type = VXFS_ACL_MASK;
180                         break;
181                 default:
182                         type = -1;
183                         talloc_free(buf);
184                         return NULL;
185                 }
186
187                 type = type & 0xff;
188
189                 /* Calculate id:
190                  * We get owner uid and owner group gid in o_uid and o_gid
191                  * Put these ids instead of -1
192                  */
193                 switch(smb_ace->a_type) {
194                 case SMB_ACL_USER:
195                         id = smb_ace->info.user.uid;
196                         break;
197                 case SMB_ACL_GROUP:
198                         id = smb_ace->info.group.gid;
199                         break;
200                 case SMB_ACL_USER_OBJ:
201                         id = o_uid;
202                         break;
203                 case SMB_ACL_GROUP_OBJ:
204                         id = o_gid;
205                         break;
206                 case SMB_ACL_MASK:
207                 case SMB_ACL_OTHER:
208                         id = -1;
209                         break;
210                 default:
211                         /* Can't happen.. */
212                         id = -1;
213                         break;
214                 }
215
216                 /* Calculate perm */
217                 perm = smb_ace->a_perm & 0xff;
218
219                 /* TYPE is the first 2 bytes of an entry */
220                 SSVAL(buf, offset, type);
221                 offset += 2;
222
223                 /* PERM is the next 2 bytes of an entry */
224                 SSVAL(buf, offset, perm);
225                 offset += 2;
226
227                 /* ID is the last 4 bytes of an entry */
228                 SIVAL(buf, offset, id);
229                 offset += 4;
230
231                 smb_ace++;
232         }
233
234         qsort(buf, count, 8, vxfs_ace_cmp);
235
236         DEBUG(10, ("vfs_vxfs: Print sorted aces:\n"));
237         vxfs_print_ace_buf(buf, count);
238
239         return buf;
240 }
241
242 /* This function gets e_buf as an arg which is sorted and created out of
243  * existing ACL. This function will compact this e_buf to c_buf where USER
244  * and GROUP aces matching with USER_OBJ and GROUP_OBJ will be merged
245  * respectively.
246  * This is similar to what posix_acls.c does. This will make sure existing
247  * acls are converted much similar to what posix_acls calculates.
248  */
249
250 static char * vxfs_compact_buf(char *e_buf, int *new_count, int count,
251                                TALLOC_CTX *mem_ctx)
252 {
253         int i, e_offset = 0, c_offset = 0;
254         uint16_t type, perm, o_perm;
255         uint32_t id, owner_id, group_id;
256         char *c_buf = NULL;
257
258
259         if (count < 2) {
260                 return NULL;
261         }
262
263         c_buf = talloc_zero_size(mem_ctx, count * 8);
264         if (!c_buf) {
265                 return NULL;
266         }
267
268         /*Copy first two enries from e_buf to c_buf
269          *These are USER_OBJ and GROUP_OBJ
270          */
271
272         memcpy(c_buf, e_buf, 16);
273
274         (*new_count) = 2;
275
276         owner_id = IVAL(e_buf, 4);
277         group_id = IVAL(e_buf, 12);
278
279         c_offset = e_offset = 16;
280
281         /* Start comparing other entries */
282         for (i = 2; i < count; i++) {
283
284                 type = SVAL(e_buf, e_offset);
285                 e_offset += 2;
286                 perm = SVAL(e_buf, e_offset);
287                 e_offset += 2;
288                 id = IVAL(e_buf, e_offset);
289                 e_offset += 4;
290
291                 switch(type) {
292                 case VXFS_ACL_USER:
293                         if (id == owner_id) {
294                                 o_perm = SVAL(c_buf, 2);
295                                 o_perm |= perm;
296                                 SSVAL(c_buf, 2, o_perm);
297                                 DEBUG(10, ("vfs_vxfs: merging with owner"
298                                           "e_type = %u,"
299                                           "e_perm = %u,"
300                                           "e_id = %u\n", (unsigned int)type,
301                                           (unsigned int)perm,
302                                           (unsigned int)id));
303                                 continue;
304                         }
305                         break;
306                 case VXFS_ACL_GROUP:
307                         if (id == group_id) {
308                                 o_perm = SVAL(c_buf, 10);
309                                 o_perm |= perm;
310                                 SSVAL(c_buf, 10, o_perm);
311                                 DEBUG(10, ("vfs_vxfs: merging with owner group"
312                                           "e_type = %u,"
313                                           "e_perm = %u,"
314                                           "e_id = %u\n", (unsigned int)type,
315                                           (unsigned int)perm,
316                                           (unsigned int)id));
317                                 continue;
318                         }
319                         break;
320                 }
321
322                 SSVAL(c_buf, c_offset, type);
323                 c_offset += 2;
324
325                 SSVAL(c_buf, c_offset, perm);
326                 c_offset += 2;
327
328                 SIVAL(c_buf, c_offset, id);
329                 c_offset += 4;
330
331                 (*new_count)++;
332         }
333         DEBUG(10, ("vfs_vxfs: new_count is %d\n", *new_count));
334         return c_buf;
335 }
336
337 /* Actually compare New ACL and existing ACL buf */
338 static bool vxfs_compare_acls(char *e_buf, char *n_buf, int n_count,
339                               int e_count) {
340
341         uint16_t e_type, n_type, e_perm, n_perm;
342         uint32_t e_id, n_id;
343         int i, offset = 0;
344
345         if (!e_buf && !n_buf) {
346                 DEBUG(10, ("vfs_vxfs: Empty buffers!\n"));
347                 return false;
348         }
349
350         if ((e_count < 2) || (n_count < 2)) {
351                 return false;
352         }
353         /*Get type from last entry from both buffers.
354          * It may or may not be ACL_MASK
355          */
356         n_type = SVAL(n_buf, offset + (8 * (n_count-1)));
357         e_type = SVAL(e_buf, offset + (8 * (e_count-1)));
358
359         /* Check for ACL_MASK entry properly. Handle all 4 cases*/
360
361         /* If ACL_MASK entry is present in any of the buffers,
362          * it will be always the last one. Calculate count to compare
363          * based on if ACL_MASK is present on new and existing ACL
364          */
365         if ((n_type != VXFS_ACL_MASK) && (e_type == VXFS_ACL_MASK)){
366                 DEBUG(10, ("vfs_vxfs: New ACL does not have mask entry,"
367                            "reduce count by 1 and compare\n"));
368                 e_count = e_count -1;
369         }
370         if ((n_type == VXFS_ACL_MASK) && (e_type != VXFS_ACL_MASK)){
371                 DEBUG(10, ("vfs_vxfs: new ACL to be set contains mask"
372                            "existing ACL does not have mask entry\n"
373                            "Need to set New ACL\n"));
374                 return false;
375         }
376
377         if (memcmp(e_buf, n_buf, (e_count * 8)) != 0) {
378                 DEBUG(10, ("vfs_vxfs: Compare with memcmp,"
379                            "buffers not same!\n"));
380                 return false;
381         }
382
383         return true;
384 }
385
386 /* In VxFS, POSIX ACLs are pointed by separate inode for each file/dir.
387  * However, files/dir share same POSIX ACL inode if ACLs are inherited
388  * from parent.
389  * To retain this behaviour, below function avoids ACL set call if
390  * underlying ACLs are already same and thus saves creating extra inode.
391  *
392  * This function will execute following steps:
393  * 1. Get existing ACL
394  * 2. Sort New ACL and existing ACL into buffers
395  * 3. Compact existing ACL buf
396  * 4. Finally compare New ACL buf and Compact buf
397  * 5. If same, return true
398  * 6. Else need to set New ACL
399  */
400
401 static bool vxfs_compare(connection_struct *conn,
402                          const struct smb_filename *smb_fname,
403                          SMB_ACL_T the_acl,
404                          SMB_ACL_TYPE_T the_acl_type)
405 {
406         char *name = smb_fname->base_name;
407         SMB_ACL_T existing_acl = NULL;
408         bool ret = false;
409         int i, count = 0;
410         TALLOC_CTX *mem_ctx = talloc_tos();
411         char *existing_buf = NULL, *new_buf = NULL, *compact_buf = NULL;
412         struct smb_filename *smb_fname = NULL;
413         int status;
414
415         DEBUG(10, ("vfs_vxfs: Getting existing ACL for %s\n", name));
416
417         existing_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, smb_fname, the_acl_type,
418                                                 mem_ctx);
419         if (existing_acl == NULL) {
420                 DEBUG(10, ("vfs_vxfs: Failed to get ACL\n"));
421                 goto out;
422         }
423
424         DEBUG(10, ("vfs_vxfs: Existing ACL count=%d\n", existing_acl->count));
425         DEBUG(10, ("vfs_vxfs: New ACL count=%d\n", the_acl->count));
426
427         if (existing_acl->count == 0) {
428                 DEBUG(10, ("vfs_vxfs: ACL count is 0, Need to set\n"));
429                 goto out;
430         }
431
432         status = SMB_VFS_STAT(conn, smb_fname);
433         if (status == -1) {
434                 DEBUG(10, ("vfs_vxfs: stat failed!\n"));
435                 goto out;
436         }
437
438         DEBUG(10, ("vfs_vxfs: Sorting existing ACL\n"));
439         existing_buf = vxfs_sort_acl(existing_acl, mem_ctx,
440                                      smb_fname->st.st_ex_uid,
441                                      smb_fname->st.st_ex_gid);
442         if (!existing_buf)
443                 goto out;
444
445         DEBUG(10, ("vfs_vxfs: Sorting new ACL\n"));
446         new_buf = vxfs_sort_acl(the_acl, mem_ctx, smb_fname->st.st_ex_uid,
447                                 smb_fname->st.st_ex_gid);
448         if (!new_buf) {
449                 goto out;
450         }
451
452         DEBUG(10, ("vfs_vxfs: Compact existing buf\n"));
453         compact_buf = vxfs_compact_buf(existing_buf, &count,
454                                        existing_acl->count,
455                                        mem_ctx);
456         if (!compact_buf) {
457                 goto out;
458         }
459
460         vxfs_print_ace_buf(compact_buf, count);
461
462         /* COmpare ACLs only if count is same or mismatch by 1 */
463         if ((count == the_acl->count) ||
464            (count == the_acl->count + 1) ||
465            (count+1 == the_acl->count)) {
466
467                 if (vxfs_compare_acls(compact_buf, new_buf, the_acl->count,
468                                      count)) {
469                         DEBUG(10, ("vfs_vxfs: ACLs matched. Not setting.\n"));
470                         ret = true;
471                         goto out;
472                 } else
473                         DEBUG(10, ("vfs_vxfs: ACLs NOT matched. Setting\n"));
474         } else {
475                 DEBUG(10, ("vfs_vxfs: ACLs count does not match. Setting\n"));
476         }
477
478 out:
479
480         TALLOC_FREE(existing_acl);
481         TALLOC_FREE(existing_buf);
482         TALLOC_FREE(compact_buf);
483         TALLOC_FREE(new_buf);
484
485         return ret;
486 }
487
488 static int vxfs_sys_acl_set_fd(vfs_handle_struct *handle,
489                                struct files_struct *fsp,
490                                SMB_ACL_TYPE_T type,
491                                SMB_ACL_T theacl)
492 {
493
494         if (vxfs_compare(fsp->conn, fsp->fsp_name, theacl,
495                          type)) {
496                 return 0;
497         }
498
499         return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, type, theacl);
500 }
501
502 static int vxfs_set_xattr(struct vfs_handle_struct *handle,
503                         const struct smb_filename *smb_fname_in,
504                         const char *name,
505                         const void *value,
506                         size_t size,
507                         int flags)
508 {
509         struct smb_filename *smb_fname = NULL;
510         bool is_dir = false;
511         int ret = 0;
512         int saved_errno = 0;
513
514         DEBUG(10, ("In vxfs_set_xattr\n"));
515
516         smb_fname = cp_smb_filename_nostream(talloc_tos(), smb_fname_in);
517         if (smb_fname == NULL) {
518                 errno = ENOMEM;
519                 return -1;
520         }
521
522         if (SMB_VFS_NEXT_STAT(handle, smb_fname) != 0) {
523                 TALLOC_FREE(smb_fname);
524                 return -1;
525         }
526
527         is_dir = S_ISDIR(smb_fname->st.st_ex_mode);
528
529         ret = vxfs_setxattr_path(smb_fname_in->base_name, name, value, size,
530                                  flags, is_dir);
531         if ((ret == 0) ||
532             ((ret == -1) && (errno != ENOTSUP) && (errno != ENOSYS))) {
533                 /*
534                  * Now remve old style xattr if it exists
535                  */
536                 SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, name);
537                 /*
538                  * Do not bother about return value
539                  */
540                 if (ret != 0) {
541                         saved_errno = errno;
542                 }
543                 goto fail;
544         }
545
546         DEBUG(10, ("Fallback to xattr\n"));
547         if (strcmp(name, XATTR_NTACL_NAME) == 0) {
548                 ret = SMB_VFS_NEXT_SETXATTR(handle, smb_fname,
549                                             XATTR_USER_NTACL,
550                                             value, size, flags);
551                 if (ret != 0) {
552                         saved_errno = errno;
553                         goto fail;
554                 }
555                 return 0;
556         }
557
558         /* Clients can't set XATTR_USER_NTACL directly. */
559         if (strcasecmp(name, XATTR_USER_NTACL) == 0) {
560                 saved_errno = EACCES;
561                 ret = -1;
562                 goto fail;
563         }
564
565         ret = SMB_VFS_NEXT_SETXATTR(handle, smb_fname,
566                                     name, value, size, flags);
567         if (ret != 0) {
568                 saved_errno = errno;
569                 goto fail;
570         }
571
572 fail:
573         TALLOC_FREE(smb_fname);
574         if (saved_errno != 0) {
575                 saved_errno = errno;
576         }
577         return ret;
578 }
579
580 static int vxfs_fset_xattr(struct vfs_handle_struct *handle,
581                            struct files_struct *fsp, const char *name,
582                            const void *value, size_t size,  int flags){
583         int ret = 0;
584
585         DEBUG(10, ("In vxfs_fset_xattr\n"));
586
587         ret = vxfs_setxattr_fd(fsp_get_io_fd(fsp), name, value, size, flags);
588         if ((ret == 0) ||
589             ((ret == -1) && (errno != ENOTSUP) && (errno != ENOSYS))) {
590                 SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
591                 return ret;
592         }
593
594         DEBUG(10, ("Fallback to xattr"));
595         if (strcmp(name, XATTR_NTACL_NAME) == 0) {
596                 return SMB_VFS_NEXT_FSETXATTR(handle, fsp, XATTR_USER_NTACL,
597                                               value, size, flags);
598         }
599
600         /* Clients can't set XATTR_USER_NTACL directly. */
601         if (strcasecmp(name, XATTR_USER_NTACL) == 0) {
602                 errno = EACCES;
603                 return -1;
604         }
605
606         return SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags);
607 }
608
609 static ssize_t vxfs_get_xattr(struct vfs_handle_struct *handle,
610                                 const struct smb_filename *smb_fname,
611                                 const char *name,
612                                 void *value,
613                                 size_t size){
614         int ret;
615
616         DEBUG(10, ("In vxfs_get_xattr\n"));
617         ret = vxfs_getxattr_path(smb_fname->base_name, name, value, size);
618         if ((ret != -1) || ((errno != ENOTSUP) &&
619                             (errno != ENOSYS) && (errno != ENODATA))) {
620                 return ret;
621         }
622
623         DEBUG(10, ("Fallback to xattr\n"));
624         if (strcmp(name, XATTR_NTACL_NAME) == 0) {
625                 return SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
626                                 XATTR_USER_NTACL, value, size);
627         }
628
629         /* Clients can't see XATTR_USER_NTACL directly. */
630         if (strcasecmp(name, XATTR_USER_NTACL) == 0) {
631                 errno = ENOATTR;
632                 return -1;
633         }
634
635         return SMB_VFS_NEXT_GETXATTR(handle, smb_fname, name, value, size);
636 }
637
638 static ssize_t vxfs_fget_xattr(struct vfs_handle_struct *handle,
639                                struct files_struct *fsp, const char *name,
640                                void *value, size_t size){
641         int ret;
642
643         DEBUG(10, ("In vxfs_fget_xattr\n"));
644
645         ret = vxfs_getxattr_fd(fsp_get_io_fd(fsp), name, value, size);
646         if ((ret != -1) || ((errno != ENOTSUP) &&
647                             (errno != ENOSYS) && (errno != ENODATA))) {
648                 return ret;
649         }
650
651         DEBUG(10, ("Fallback to xattr\n"));
652         if (strcmp(name, XATTR_NTACL_NAME) == 0) {
653                 return SMB_VFS_NEXT_FGETXATTR(handle, fsp, XATTR_USER_NTACL,
654                                               value, size);
655         }
656
657         /* Clients can't see XATTR_USER_NTACL directly. */
658         if (strcasecmp(name, XATTR_USER_NTACL) == 0) {
659                 errno = ENOATTR;
660                 return -1;
661         }
662
663         return SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
664 }
665
666 static int vxfs_remove_xattr(struct vfs_handle_struct *handle,
667                                 const struct smb_filename *smb_fname_in,
668                                 const char *name)
669 {
670         bool is_dir = false;
671         int ret = 0, ret_new = 0, old_errno;
672         struct smb_filename *smb_fname = NULL;
673
674         DEBUG(10, ("In vxfs_remove_xattr\n"));
675
676         smb_fname = cp_smb_filename_nostream(talloc_tos(), smb_fname_in);
677         if (smb_fname == NULL) {
678                 errno = ENOMEM;
679                 return -1;
680         }
681
682         /* Remove with old way */
683         if (strcmp(name, XATTR_NTACL_NAME) == 0) {
684                 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname,
685                                                XATTR_USER_NTACL);
686         } else {
687                 if (strcasecmp(name, XATTR_USER_NTACL) != 0) {
688                         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname,
689                                                        name);
690                 }
691         }
692         /* Remove with new way */
693         old_errno = errno;
694
695         if (SMB_VFS_NEXT_STAT(handle, smb_fname) != 0) {
696                 TALLOC_FREE(smb_fname);
697                 return -1;
698         }
699
700         is_dir = S_ISDIR(smb_fname->st.st_ex_mode);
701         TALLOC_FREE(smb_fname);
702         /*
703          * If both fail, return failuer else return whichever succeeded
704          */
705         ret_new = vxfs_removexattr_path(smb_fname_in->base_name, name, is_dir);
706         if (errno == ENOTSUP || errno == ENOSYS) {
707                 errno = old_errno;
708         }
709         if ((ret_new != -1) && (ret == -1)) {
710                 ret = ret_new;
711         }
712
713         return ret;
714
715 }
716
717 static int vxfs_fremove_xattr(struct vfs_handle_struct *handle,
718                               struct files_struct *fsp, const char *name){
719         int ret = 0, ret_new = 0, old_errno;
720
721         DEBUG(10, ("In vxfs_fremove_xattr\n"));
722
723         /* Remove with old way */
724         if (strcmp(name, XATTR_NTACL_NAME) == 0) {
725                 ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp,
726                                                 XATTR_USER_NTACL);
727         } else {
728                 /* Clients can't remove XATTR_USER_NTACL directly. */
729                 if (strcasecmp(name, XATTR_USER_NTACL) != 0) {
730                         ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp,
731                                                         name);
732                 }
733         }
734         old_errno = errno;
735
736         /* Remove with new way */
737         ret_new = vxfs_removexattr_fd(fsp_get_io_fd(fsp), name);
738         /*
739          * If both fail, return failuer else return whichever succeeded
740          */
741         if (errno == ENOTSUP || errno == ENOSYS) {
742                 errno = old_errno;
743         }
744         if ((ret_new != -1) && (ret == -1)) {
745                 ret = ret_new;
746         }
747
748         return ret;
749
750 }
751
752 static size_t vxfs_filter_list(char *list, size_t size)
753 {
754         char *str = list;
755
756         while (str - list < size) {
757                 size_t element_len = strlen(str) + 1;
758                 if (strcasecmp(str, XATTR_USER_NTACL) == 0) {
759                         memmove(str,
760                                 str + element_len,
761                                 size - (str - list) - element_len);
762                         size -= element_len;
763                         continue;
764                 }
765                 str += element_len;
766         }
767         return size;
768 }
769
770 static ssize_t vxfs_flistxattr(struct vfs_handle_struct *handle,
771                                 struct files_struct *fsp, char *list,
772                                 size_t size)
773 {
774         ssize_t result;
775
776         result = vxfs_listxattr_fd(fsp_get_io_fd(fsp), list, size);
777         if (result >= 0 || ((errno != ENOTSUP) && (errno != ENOSYS))) {
778                 return result;
779         }
780
781         result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
782
783         if (result <= 0) {
784                 return result;
785         }
786
787         /* Remove any XATTR_USER_NTACL elements from the returned list. */
788         result = vxfs_filter_list(list, result);
789
790         return result;
791 }
792
793 static NTSTATUS vxfs_set_ea_dos_attributes(struct vfs_handle_struct *handle,
794                                            const struct smb_filename *smb_fname,
795                                            uint32_t dosmode)
796 {
797         NTSTATUS        err;
798         int                     ret = 0;
799         bool            attrset = false;
800         bool            is_dir = false;
801
802         DBG_DEBUG("Entered function\n");
803
804         is_dir = S_ISDIR(smb_fname->st.st_ex_mode);
805         if (!(dosmode & FILE_ATTRIBUTE_READONLY)) {
806                 ret = vxfs_checkwxattr_path(smb_fname->base_name);
807                 if (ret == -1) {
808                         DBG_DEBUG("ret:%d\n", ret);
809                         if ((errno != EOPNOTSUPP) && (errno != ENOENT)) {
810                                 return map_nt_error_from_unix(errno);
811                         }
812                 }
813         }
814         if (dosmode & FILE_ATTRIBUTE_READONLY) {
815                 ret = vxfs_setwxattr_path(smb_fname->base_name, is_dir);
816                 DBG_DEBUG("ret:%d\n", ret);
817                 if (ret == -1) {
818                         if ((errno != EOPNOTSUPP) && (errno != EINVAL)) {
819                                 return map_nt_error_from_unix(errno);
820                         }
821                 } else {
822                         attrset = true;
823                 }
824         }
825         err = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle, smb_fname, dosmode);
826         if (!NT_STATUS_IS_OK(err)) {
827                 if (attrset) {
828                         ret = vxfs_clearwxattr_path(smb_fname->base_name, is_dir);
829                         DBG_DEBUG("ret:%d\n", ret);
830                         if ((ret == -1) && (errno != ENOENT)) {
831                                 return map_nt_error_from_unix(errno);
832                         }
833                 }
834         }
835
836         return err;
837 }
838
839 static NTSTATUS vxfs_fset_ea_dos_attributes(struct vfs_handle_struct *handle,
840                                             struct files_struct *fsp,
841                                             uint32_t dosmode)
842 {
843         NTSTATUS        err;
844         int             ret = 0;
845         bool            attrset = false;
846
847         DBG_DEBUG("Entered function\n");
848
849         if (!(dosmode & FILE_ATTRIBUTE_READONLY)) {
850                 ret = vxfs_checkwxattr_fd(fsp_get_io_fd(fsp));
851                 if (ret == -1) {
852                         DBG_DEBUG("ret:%d\n", ret);
853                         if ((errno != EOPNOTSUPP) && (errno != ENOENT)) {
854                                 return map_nt_error_from_unix(errno);
855                         }
856                 }
857         }
858         if (dosmode & FILE_ATTRIBUTE_READONLY) {
859                 ret = vxfs_setwxattr_fd(fsp_get_io_fd(fsp));
860                 DBG_DEBUG("ret:%d\n", ret);
861                 if (ret == -1) {
862                         if ((errno != EOPNOTSUPP) && (errno != EINVAL)) {
863                                 return map_nt_error_from_unix(errno);
864                         }
865                 } else {
866                         attrset = true;
867                 }
868         }
869         err = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
870         if (!NT_STATUS_IS_OK(err)) {
871                 if (attrset) {
872                         ret = vxfs_clearwxattr_fd(fsp_get_io_fd(fsp));
873                         DBG_DEBUG("ret:%d\n", ret);
874                         if ((ret == -1) && (errno != ENOENT)) {
875                                 return map_nt_error_from_unix(errno);
876                         }
877                 }
878         }
879         return err;
880 }
881
882 static int vfs_vxfs_connect(struct vfs_handle_struct *handle,
883                             const char *service, const char *user)
884 {
885
886         int ret;
887
888         ret  = SMB_VFS_NEXT_CONNECT(handle, service, user);
889         if (ret < 0) {
890                 return ret;
891         }
892
893         vxfs_init();
894
895         return 0;
896 }
897
898 static struct vfs_fn_pointers vfs_vxfs_fns = {
899         .connect_fn = vfs_vxfs_connect,
900
901 #ifdef VXFS_ACL_SHARE
902         .sys_acl_set_fd_fn = vxfs_sys_acl_set_fd,
903 #endif
904
905         .set_dos_attributes_fn = vxfs_set_ea_dos_attributes,
906         .fset_dos_attributes_fn = vxfs_fset_ea_dos_attributes,
907         .getxattr_fn = vxfs_get_xattr,
908         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
909         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
910         .fgetxattr_fn = vxfs_fget_xattr,
911         .flistxattr_fn = vxfs_flistxattr,
912         .removexattr_fn = vxfs_remove_xattr,
913         .fremovexattr_fn = vxfs_fremove_xattr,
914         .setxattr_fn = vxfs_set_xattr,
915         .fsetxattr_fn = vxfs_fset_xattr,
916 };
917
918 static_decl_vfs;
919 NTSTATUS vfs_vxfs_init(TALLOC_CTX *ctx)
920 {
921         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "vxfs",
922                                 &vfs_vxfs_fns);
923 }