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