f455afd4a45af123df5ac80e451cfa433c762683
[samba.git] / source3 / modules / vfs_catia.c
1 /*
2  * Catia VFS module
3  *
4  * Implement a fixed mapping of forbidden NT characters in filenames that are
5  * used a lot by the CAD package Catia.
6  *
7  * Yes, this a BAD BAD UGLY INCOMPLETE hack, but it helps quite some people
8  * out there. Catia V4 on AIX uses characters like "<*$ a *lot*, all forbidden
9  * under Windows...
10  *
11  * Copyright (C) Volker Lendecke, 2005
12  * Copyright (C) Aravind Srinivasan, 2009
13  * Copyright (C) Guenter Kukkukk, 2013
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, see <http://www.gnu.org/licenses/>.
27  */
28
29
30 #include "includes.h"
31 #include "smbd/smbd.h"
32
33 static int vfs_catia_debug_level = DBGC_VFS;
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS vfs_catia_debug_level
37
38 #define GLOBAL_SNUM     0xFFFFFFF
39 #define MAP_SIZE        0xFF
40 #define MAP_NUM         0x101 /* max unicode charval / MAP_SIZE */
41 #define T_OFFSET(_v_)   ((_v_ % MAP_SIZE))
42 #define T_START(_v_)    (((_v_ / MAP_SIZE) * MAP_SIZE))
43 #define T_PICK(_v_)     ((_v_ / MAP_SIZE))
44
45 struct char_mappings {
46         smb_ucs2_t entry[MAP_SIZE][2];
47 };
48
49 struct share_mapping_entry {
50         int snum;
51         struct share_mapping_entry *next;
52         struct char_mappings **mappings;
53 };
54
55 struct share_mapping_entry *srt_head = NULL;
56
57 static bool build_table(struct char_mappings **cmaps, int value)
58 {
59         int i;
60         int start = T_START(value);
61
62         (*cmaps) = talloc_zero(NULL, struct char_mappings);
63
64         if (!*cmaps)
65                 return False;
66
67         for (i = 0; i < MAP_SIZE;i++) {
68                 (*cmaps)->entry[i][vfs_translate_to_unix] = start + i;
69                 (*cmaps)->entry[i][vfs_translate_to_windows] = start + i;
70         }
71
72         return True;
73 }
74
75 static void set_tables(struct char_mappings **cmaps,
76                        long unix_map,
77                        long windows_map)
78 {
79         int i;
80
81         /* set unix -> windows */
82         i = T_OFFSET(unix_map);
83         cmaps[T_PICK(unix_map)]->entry[i][vfs_translate_to_windows] = windows_map;
84
85         /* set windows -> unix */
86         i = T_OFFSET(windows_map);
87         cmaps[T_PICK(windows_map)]->entry[i][vfs_translate_to_unix] = unix_map;
88 }
89
90 static bool build_ranges(struct char_mappings **cmaps,
91                          long unix_map,
92                          long windows_map)
93 {
94
95         if (!cmaps[T_PICK(unix_map)]) {
96                 if (!build_table(&cmaps[T_PICK(unix_map)], unix_map))
97                         return False;
98         }
99
100         if (!cmaps[T_PICK(windows_map)]) {
101                 if (!build_table(&cmaps[T_PICK(windows_map)], windows_map))
102                         return False;
103         }
104
105         set_tables(cmaps, unix_map, windows_map);
106
107         return True;
108 }
109
110 static struct share_mapping_entry *get_srt(connection_struct *conn,
111                                            struct share_mapping_entry **global)
112 {
113         struct share_mapping_entry *share;
114
115         for (share = srt_head; share != NULL; share = share->next) {
116                 if (share->snum == GLOBAL_SNUM)
117                         (*global) = share;
118
119                 if (share->snum == SNUM(conn))
120                         return share;
121         }
122
123         return share;
124 }
125
126 static struct share_mapping_entry *add_srt(int snum, const char **mappings)
127 {
128
129         char *tmp;
130         fstring mapping;
131         int i;
132         long unix_map, windows_map;
133         struct share_mapping_entry *ret = NULL;
134
135         ret = (struct share_mapping_entry *)
136                 TALLOC_ZERO(NULL, sizeof(struct share_mapping_entry) +
137                 (mappings ? (MAP_NUM * sizeof(struct char_mappings *)) : 0));
138
139         if (!ret)
140                 return ret;
141
142         ret->snum = snum;
143
144         if (mappings) {
145                 ret->mappings = (struct char_mappings**) ((unsigned char*) ret +
146                     sizeof(struct share_mapping_entry));
147                 memset(ret->mappings, 0,
148                     MAP_NUM * sizeof(struct char_mappings *));
149         } else {
150                 ret->mappings = NULL;
151                 return ret;
152         }
153
154         /*
155          * catia mappings are of the form :
156          * UNIX char (in 0xnn hex) : WINDOWS char (in 0xnn hex)
157          *
158          * multiple mappings are comma separated in smb.conf
159          */
160         for (i=0;mappings[i];i++) {
161                 fstrcpy(mapping, mappings[i]);
162                 unix_map = strtol(mapping, &tmp, 16);
163                 if (unix_map == 0 && errno == EINVAL) {
164                         DEBUG(0, ("INVALID CATIA MAPPINGS - %s\n", mapping));
165                         continue;
166                 }
167                 windows_map = strtol(++tmp, NULL, 16);
168                 if (windows_map == 0 && errno == EINVAL) {
169                         DEBUG(0, ("INVALID CATIA MAPPINGS - %s\n", mapping));
170                         continue;
171                 }
172
173                 if (!build_ranges(ret->mappings, unix_map, windows_map)) {
174                         DEBUG(0, ("TABLE ERROR - CATIA MAPPINGS - %s\n", mapping));
175                         continue;
176                 }
177         }
178
179         ret->next = srt_head;
180         srt_head = ret;
181
182         return ret;
183 }
184
185 static bool init_mappings(connection_struct *conn,
186                           struct share_mapping_entry **selected_out)
187 {
188         const char **mappings = NULL;
189         struct share_mapping_entry *share_level = NULL;
190         struct share_mapping_entry *global = NULL;
191
192         /* check srt cache */
193         share_level = get_srt(conn, &global);
194         if (share_level) {
195                 *selected_out = share_level;
196                 return (share_level->mappings != NULL);
197         }
198
199         /* see if we have a global setting */
200         if (!global) {
201                 /* global setting */
202                 mappings = lp_parm_string_list(-1, "catia", "mappings", NULL);
203                 global = add_srt(GLOBAL_SNUM, mappings);
204         }
205
206         /* no global setting - what about share level ? */
207         mappings = lp_parm_string_list(SNUM(conn), "catia", "mappings", NULL);
208         share_level = add_srt(SNUM(conn), mappings);
209
210         if (share_level->mappings) {
211                 (*selected_out) = share_level;
212                 return True;
213         }
214         if (global->mappings) {
215                 share_level->mappings = global->mappings;
216                 (*selected_out) = share_level;
217                 return True;
218         }
219
220         return False;
221 }
222
223 static NTSTATUS catia_string_replace_allocate(connection_struct *conn,
224                                               const char *name_in,
225                                               char **mapped_name,
226                                         enum vfs_translate_direction direction)
227 {
228         static smb_ucs2_t *tmpbuf = NULL;
229         smb_ucs2_t *ptr;
230         struct share_mapping_entry *selected;
231         struct char_mappings *map = NULL;
232         size_t converted_size;
233         TALLOC_CTX *ctx = talloc_tos();
234
235         if (!init_mappings(conn, &selected)) {
236                 /* No mappings found. Just use the old name */
237                 *mapped_name = talloc_strdup(NULL, name_in);
238                 if (!*mapped_name) {
239                         errno = ENOMEM;
240                         return NT_STATUS_NO_MEMORY;
241                 }
242                 return NT_STATUS_OK;
243         }
244
245         if ((push_ucs2_talloc(ctx, &tmpbuf, name_in,
246                               &converted_size)) == false) {
247                 return map_nt_error_from_unix(errno);
248         }
249         ptr = tmpbuf;
250         for(;*ptr;ptr++) {
251                 if (*ptr == 0)
252                         break;
253                 map = selected->mappings[T_PICK((*ptr))];
254
255                 /* nothing to do */
256                 if (!map)
257                         continue;
258
259                 *ptr = map->entry[T_OFFSET((*ptr))][direction];
260         }
261
262         if ((pull_ucs2_talloc(ctx, mapped_name, tmpbuf,
263                               &converted_size)) == false) {
264                 TALLOC_FREE(tmpbuf);
265                 return map_nt_error_from_unix(errno);
266         }
267         TALLOC_FREE(tmpbuf);
268         return NT_STATUS_OK;
269 }
270
271 static DIR *catia_opendir(vfs_handle_struct *handle,
272                                      const char *fname,
273                                      const char *mask,
274                                      uint32_t attr)
275 {
276         char *name_mapped = NULL;
277         NTSTATUS status;
278         DIR *ret;
279
280         status = catia_string_replace_allocate(handle->conn, fname,
281                                         &name_mapped, vfs_translate_to_unix);
282         if (!NT_STATUS_IS_OK(status)) {
283                 errno = map_errno_from_nt_status(status);
284                 return NULL;
285         }
286
287         ret = SMB_VFS_NEXT_OPENDIR(handle, name_mapped, mask, attr);
288         TALLOC_FREE(name_mapped);
289
290         return ret;
291 }
292
293 /*
294  * TRANSLATE_NAME call which converts the given name to
295  * "WINDOWS displayable" name
296  */
297 static NTSTATUS catia_translate_name(struct vfs_handle_struct *handle,
298                                      const char *orig_name,
299                                      enum vfs_translate_direction direction,
300                                      TALLOC_CTX *mem_ctx,
301                                      char **pmapped_name)
302 {
303         char *name = NULL;
304         char *mapped_name;
305         NTSTATUS status, ret;
306
307         /*
308          * Copy the supplied name and free the memory for mapped_name,
309          * already allocated by the caller.
310          * We will be allocating new memory for mapped_name in
311          * catia_string_replace_allocate
312          */
313         name = talloc_strdup(talloc_tos(), orig_name);
314         if (!name) {
315                 errno = ENOMEM;
316                 return NT_STATUS_NO_MEMORY;
317         }
318         status = catia_string_replace_allocate(handle->conn, name,
319                         &mapped_name, direction);
320
321         TALLOC_FREE(name);
322         if (!NT_STATUS_IS_OK(status)) {
323                 return status;
324         }
325
326         ret = SMB_VFS_NEXT_TRANSLATE_NAME(handle, mapped_name, direction,
327                                           mem_ctx, pmapped_name);
328
329         if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
330                 *pmapped_name = talloc_move(mem_ctx, &mapped_name);
331                 /* we need to return the former translation result here */
332                 ret = status;
333         } else {
334                 TALLOC_FREE(mapped_name);
335         }
336
337         return ret;
338 }
339
340 static int catia_open(vfs_handle_struct *handle,
341                       struct smb_filename *smb_fname,
342                       files_struct *fsp,
343                       int flags,
344                       mode_t mode)
345 {
346         char *name_mapped = NULL;
347         char *tmp_base_name;
348         int ret;
349         NTSTATUS status;
350
351         tmp_base_name = smb_fname->base_name;
352         status = catia_string_replace_allocate(handle->conn,
353                                         smb_fname->base_name,
354                                         &name_mapped, vfs_translate_to_unix);
355         if (!NT_STATUS_IS_OK(status)) {
356                 errno = map_errno_from_nt_status(status);
357                 return -1;
358         }
359
360         smb_fname->base_name = name_mapped;
361         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
362         smb_fname->base_name = tmp_base_name;
363         TALLOC_FREE(name_mapped);
364
365         return ret;
366 }
367
368 static int catia_rename(vfs_handle_struct *handle,
369                         const struct smb_filename *smb_fname_src,
370                         const struct smb_filename *smb_fname_dst)
371 {
372         TALLOC_CTX *ctx = talloc_tos();
373         struct smb_filename *smb_fname_src_tmp = NULL;
374         struct smb_filename *smb_fname_dst_tmp = NULL;
375         char *src_name_mapped = NULL;
376         char *dst_name_mapped = NULL;
377         NTSTATUS status;
378         int ret = -1;
379
380         status = catia_string_replace_allocate(handle->conn,
381                                 smb_fname_src->base_name,
382                                 &src_name_mapped, vfs_translate_to_unix);
383         if (!NT_STATUS_IS_OK(status)) {
384                 errno = map_errno_from_nt_status(status);
385                 return -1;
386         }
387
388         status = catia_string_replace_allocate(handle->conn,
389                                 smb_fname_dst->base_name,
390                                 &dst_name_mapped, vfs_translate_to_unix);
391         if (!NT_STATUS_IS_OK(status)) {
392                 errno = map_errno_from_nt_status(status);
393                 return -1;
394         }
395
396         /* Setup temporary smb_filename structs. */
397         smb_fname_src_tmp = cp_smb_filename(ctx, smb_fname_src);
398         if (smb_fname_src_tmp == NULL) {
399                 errno = ENOMEM;
400                 goto out;
401         }
402
403         smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
404         if (smb_fname_dst_tmp == NULL) {
405                 errno = ENOMEM;
406                 goto out;
407         }
408
409         smb_fname_src_tmp->base_name = src_name_mapped;
410         smb_fname_dst_tmp->base_name = dst_name_mapped; 
411         DEBUG(10, ("converted old name: %s\n",
412                                 smb_fname_str_dbg(smb_fname_src_tmp)));
413         DEBUG(10, ("converted new name: %s\n",
414                                 smb_fname_str_dbg(smb_fname_dst_tmp)));
415
416         ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_tmp,
417                         smb_fname_dst_tmp);
418 out:
419         TALLOC_FREE(src_name_mapped);
420         TALLOC_FREE(dst_name_mapped);
421         TALLOC_FREE(smb_fname_src_tmp);
422         TALLOC_FREE(smb_fname_dst_tmp);
423         return ret;
424 }
425
426 static int catia_stat(vfs_handle_struct *handle,
427                       struct smb_filename *smb_fname)
428 {
429         char *name = NULL;
430         char *tmp_base_name;
431         int ret;
432         NTSTATUS status;
433
434         status = catia_string_replace_allocate(handle->conn,
435                                 smb_fname->base_name,
436                                 &name, vfs_translate_to_unix);
437         if (!NT_STATUS_IS_OK(status)) {
438                 errno = map_errno_from_nt_status(status);
439                 return -1;
440         }
441
442         tmp_base_name = smb_fname->base_name;
443         smb_fname->base_name = name;
444
445         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
446         smb_fname->base_name = tmp_base_name;
447
448         TALLOC_FREE(name);
449         return ret;
450 }
451
452 static int catia_lstat(vfs_handle_struct *handle,
453                        struct smb_filename *smb_fname)
454 {
455         char *name = NULL;
456         char *tmp_base_name;
457         int ret;
458         NTSTATUS status;
459
460         status = catia_string_replace_allocate(handle->conn,
461                                 smb_fname->base_name,
462                                 &name, vfs_translate_to_unix);
463         if (!NT_STATUS_IS_OK(status)) {
464                 errno = map_errno_from_nt_status(status);
465                 return -1;
466         }
467
468         tmp_base_name = smb_fname->base_name;
469         smb_fname->base_name = name;
470
471         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
472         smb_fname->base_name = tmp_base_name;
473         TALLOC_FREE(name);
474
475         return ret;
476 }
477
478 static int catia_unlink(vfs_handle_struct *handle,
479                         const struct smb_filename *smb_fname)
480 {
481         struct smb_filename *smb_fname_tmp = NULL;
482         char *name = NULL;
483         NTSTATUS status;
484         int ret;
485
486         status = catia_string_replace_allocate(handle->conn,
487                                         smb_fname->base_name,
488                                         &name, vfs_translate_to_unix);
489         if (!NT_STATUS_IS_OK(status)) {
490                 errno = map_errno_from_nt_status(status);
491                 return -1;
492         }
493
494         /* Setup temporary smb_filename structs. */
495         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
496         if (smb_fname_tmp == NULL) {
497                 errno = ENOMEM;
498                 return -1;
499         }
500
501         smb_fname_tmp->base_name = name;
502         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
503         TALLOC_FREE(smb_fname_tmp);
504         TALLOC_FREE(name);
505
506         return ret;
507 }
508
509 static int catia_chown(vfs_handle_struct *handle,
510                        const char *path,
511                        uid_t uid,
512                        gid_t gid)
513 {
514         char *name = NULL;
515         NTSTATUS status;
516         int ret;
517
518         status = catia_string_replace_allocate(handle->conn, path,
519                                         &name, vfs_translate_to_unix);
520         if (!NT_STATUS_IS_OK(status)) {
521                 errno = map_errno_from_nt_status(status);
522                 return -1;
523         }
524
525         ret = SMB_VFS_NEXT_CHOWN(handle, name, uid, gid);
526         TALLOC_FREE(name);
527
528         return ret;
529 }
530
531 static int catia_lchown(vfs_handle_struct *handle,
532                         const char *path,
533                         uid_t uid,
534                         gid_t gid)
535 {
536         char *name = NULL;
537         NTSTATUS status;
538         int ret;
539
540         status = catia_string_replace_allocate(handle->conn, path,
541                                         &name, vfs_translate_to_unix);
542         if (!NT_STATUS_IS_OK(status)) {
543                 errno = map_errno_from_nt_status(status);
544                 return -1;
545         }
546
547         ret = SMB_VFS_NEXT_LCHOWN(handle, name, uid, gid);
548         TALLOC_FREE(name);
549
550         return ret;
551 }
552
553 static int catia_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
554 {
555         char *name = NULL;
556         NTSTATUS status;
557         int ret;
558
559         status = catia_string_replace_allocate(handle->conn, path,
560                                         &name, vfs_translate_to_unix);
561         if (!NT_STATUS_IS_OK(status)) {
562                 errno = map_errno_from_nt_status(status);
563                 return -1;
564         }
565
566         ret = SMB_VFS_NEXT_CHMOD(handle, name, mode);
567         TALLOC_FREE(name);
568
569         return ret;
570 }
571
572 static int catia_rmdir(vfs_handle_struct *handle,
573                        const char *path)
574 {
575         char *name = NULL;
576         NTSTATUS status;
577         int ret;
578
579         status = catia_string_replace_allocate(handle->conn, path,
580                                         &name, vfs_translate_to_unix);
581         if (!NT_STATUS_IS_OK(status)) {
582                 errno = map_errno_from_nt_status(status);
583                 return -1;
584         }
585
586         ret = SMB_VFS_NEXT_RMDIR(handle, name);
587         TALLOC_FREE(name);
588
589         return ret;
590 }
591
592 static int catia_mkdir(vfs_handle_struct *handle,
593                        const char *path,
594                        mode_t mode)
595 {
596         char *name = NULL;
597         NTSTATUS status;
598         int ret;
599
600         status = catia_string_replace_allocate(handle->conn, path,
601                                          &name, vfs_translate_to_unix);
602         if (!NT_STATUS_IS_OK(status)) {
603                 errno = map_errno_from_nt_status(status);
604                 return -1;
605         }
606
607         ret = SMB_VFS_NEXT_MKDIR(handle, name, mode);
608         TALLOC_FREE(name);
609
610         return ret;
611 }
612
613 static int catia_chdir(vfs_handle_struct *handle,
614                        const char *path)
615 {
616         char *name = NULL;
617         NTSTATUS status;
618         int ret;
619
620         status = catia_string_replace_allocate(handle->conn, path,
621                                         &name, vfs_translate_to_unix);
622         if (!NT_STATUS_IS_OK(status)) {
623                 errno = map_errno_from_nt_status(status);
624                 return -1;
625         }
626
627         ret = SMB_VFS_NEXT_CHDIR(handle, name);
628         TALLOC_FREE(name);
629
630         return ret;
631 }
632
633 static int catia_ntimes(vfs_handle_struct *handle,
634                         const struct smb_filename *smb_fname,
635                         struct smb_file_time *ft)
636 {
637         struct smb_filename *smb_fname_tmp = NULL;
638         char *name = NULL;
639         NTSTATUS status;
640         int ret;
641
642         status = catia_string_replace_allocate(handle->conn,
643                                 smb_fname->base_name,
644                                 &name, vfs_translate_to_unix);
645         if (!NT_STATUS_IS_OK(status)) {
646                 errno = map_errno_from_nt_status(status);
647                 return -1;
648         }
649
650         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
651         if (smb_fname_tmp == NULL) {
652                 errno = ENOMEM;
653                 return -1;
654         }
655
656         smb_fname_tmp->base_name = name;
657         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
658         TALLOC_FREE(name);
659         TALLOC_FREE(smb_fname_tmp);
660
661         return ret;
662 }
663
664 static char *
665 catia_realpath(vfs_handle_struct *handle, const char *path)
666 {
667         char *mapped_name = NULL;
668         NTSTATUS status;
669         char *ret = NULL;
670
671         status = catia_string_replace_allocate(handle->conn, path,
672                                         &mapped_name, vfs_translate_to_unix);
673         if (!NT_STATUS_IS_OK(status)) {
674                 errno = map_errno_from_nt_status(status);
675                 return NULL;
676         }
677
678         ret = SMB_VFS_NEXT_REALPATH(handle, mapped_name);
679         TALLOC_FREE(mapped_name);
680
681         return ret;
682 }
683
684 static int catia_chflags(struct vfs_handle_struct *handle,
685                          const char *path, unsigned int flags)
686 {
687         char *mapped_name = NULL;
688         NTSTATUS status;
689         int ret;
690
691         status = catia_string_replace_allocate(handle->conn, path,
692                                         &mapped_name, vfs_translate_to_unix);
693         if (!NT_STATUS_IS_OK(status)) {
694                 errno = map_errno_from_nt_status(status);
695                 return -1;
696         }
697
698         ret = SMB_VFS_NEXT_CHFLAGS(handle, mapped_name, flags);
699         TALLOC_FREE(mapped_name);
700
701         return ret;
702 }
703
704 static NTSTATUS
705 catia_streaminfo(struct vfs_handle_struct *handle,
706                  struct files_struct *fsp,
707                  const char *path,
708                  TALLOC_CTX *mem_ctx,
709                  unsigned int *_num_streams,
710                  struct stream_struct **_streams)
711 {
712         char *mapped_name = NULL;
713         NTSTATUS status;
714         int i;
715         unsigned int num_streams = 0;
716         struct stream_struct *streams = NULL;
717
718         *_num_streams = 0;
719         *_streams = NULL;
720
721         status = catia_string_replace_allocate(handle->conn, path,
722                                         &mapped_name, vfs_translate_to_unix);
723         if (!NT_STATUS_IS_OK(status)) {
724                 errno = map_errno_from_nt_status(status);
725                 return status;
726         }
727
728         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, mapped_name,
729                                          mem_ctx, &num_streams, &streams);
730         TALLOC_FREE(mapped_name);
731         if (!NT_STATUS_IS_OK(status)) {
732                 return status;
733         }
734
735         /*
736          * Translate stream names just like the base names
737          */
738         for (i = 0; i < num_streams; i++) {
739                 /*
740                  * Strip ":" prefix and ":$DATA" suffix to get a
741                  * "pure" stream name and only translate that.
742                  */
743                 void *old_ptr = streams[i].name;
744                 char *stream_name = streams[i].name + 1;
745                 char *stream_type = strrchr_m(stream_name, ':');
746
747                 if (stream_type != NULL) {
748                         *stream_type = '\0';
749                         stream_type += 1;
750                 }
751
752                 status = catia_string_replace_allocate(handle->conn, stream_name,
753                                                        &mapped_name, vfs_translate_to_windows);
754                 if (!NT_STATUS_IS_OK(status)) {
755                         TALLOC_FREE(streams);
756                         return status;
757                 }
758
759                 if (stream_type != NULL) {
760                         streams[i].name = talloc_asprintf(streams, ":%s:%s",
761                                                           mapped_name, stream_type);
762                 } else {
763                         streams[i].name = talloc_asprintf(streams, ":%s",
764                                                           mapped_name);
765                 }
766                 TALLOC_FREE(mapped_name);
767                 TALLOC_FREE(old_ptr);
768                 if (streams[i].name == NULL) {
769                         TALLOC_FREE(streams);
770                         return NT_STATUS_NO_MEMORY;
771                 }
772         }
773
774         *_num_streams = num_streams;
775         *_streams = streams;
776         return NT_STATUS_OK;
777 }
778
779 static NTSTATUS
780 catia_get_nt_acl(struct vfs_handle_struct *handle,
781                  const char *path,
782                  uint32_t security_info,
783                  TALLOC_CTX *mem_ctx,
784                  struct security_descriptor **ppdesc)
785 {
786         char *mapped_name = NULL;
787         NTSTATUS status;
788
789         status = catia_string_replace_allocate(handle->conn,
790                                 path, &mapped_name, vfs_translate_to_unix);
791         if (!NT_STATUS_IS_OK(status)) {
792                 errno = map_errno_from_nt_status(status);
793                 return status;
794         }
795         status = SMB_VFS_NEXT_GET_NT_ACL(handle, mapped_name,
796                                          security_info, mem_ctx, ppdesc);
797         TALLOC_FREE(mapped_name);
798
799         return status;
800 }
801
802 static int
803 catia_chmod_acl(vfs_handle_struct *handle,
804                 const char *path,
805                 mode_t mode)
806 {
807         char *mapped_name = NULL;
808         NTSTATUS status;
809         int ret;
810
811         status = catia_string_replace_allocate(handle->conn,
812                                 path, &mapped_name, vfs_translate_to_unix);
813         if (!NT_STATUS_IS_OK(status)) {
814                 errno = map_errno_from_nt_status(status);
815                 return -1;
816         }
817
818         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, mapped_name, mode);
819         TALLOC_FREE(mapped_name);
820         return ret;
821 }
822
823 static SMB_ACL_T
824 catia_sys_acl_get_file(vfs_handle_struct *handle,
825                        const char *path,
826                        SMB_ACL_TYPE_T type,
827                        TALLOC_CTX *mem_ctx)
828 {
829         char *mapped_name = NULL;
830         NTSTATUS status;
831         SMB_ACL_T ret;
832
833         status = catia_string_replace_allocate(handle->conn,
834                                 path, &mapped_name, vfs_translate_to_unix);
835         if (!NT_STATUS_IS_OK(status)) {
836                 errno = map_errno_from_nt_status(status);
837                 return NULL;
838         }
839
840         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, mapped_name, type, mem_ctx);
841         TALLOC_FREE(mapped_name);
842
843         return ret;
844 }
845
846 static int
847 catia_sys_acl_set_file(vfs_handle_struct *handle,
848                        const char *path,
849                        SMB_ACL_TYPE_T type,
850                        SMB_ACL_T theacl)
851 {
852         char *mapped_name = NULL;
853         NTSTATUS status;
854         int ret;
855
856         status = catia_string_replace_allocate(handle->conn,
857                                 path, &mapped_name, vfs_translate_to_unix);
858         if (!NT_STATUS_IS_OK(status)) {
859                 errno = map_errno_from_nt_status(status);
860                 return -1;
861         }
862
863         ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, mapped_name, type, theacl);
864         TALLOC_FREE(mapped_name);
865
866         return ret;
867 }
868
869 static int
870 catia_sys_acl_delete_def_file(vfs_handle_struct *handle,
871                               const char *path)
872 {
873         char *mapped_name = NULL;
874         NTSTATUS status;
875         int ret;
876
877         status = catia_string_replace_allocate(handle->conn,
878                                 path, &mapped_name, vfs_translate_to_unix);
879         if (!NT_STATUS_IS_OK(status)) {
880                 errno = map_errno_from_nt_status(status);
881                 return -1;
882         }
883
884         ret = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, mapped_name);
885         TALLOC_FREE(mapped_name);
886
887         return ret;
888 }
889
890 static ssize_t
891 catia_getxattr(vfs_handle_struct *handle, const char *path,
892                const char *name, void *value, size_t size)
893 {
894         char *mapped_name = NULL;
895         NTSTATUS status;
896         ssize_t ret;
897
898         status = catia_string_replace_allocate(handle->conn,
899                                 name, &mapped_name, vfs_translate_to_unix);
900         if (!NT_STATUS_IS_OK(status)) {
901                 errno = map_errno_from_nt_status(status);
902                 return -1;
903         }
904
905
906         ret = SMB_VFS_NEXT_GETXATTR(handle, path, mapped_name, value, size);
907         TALLOC_FREE(mapped_name);
908
909         return ret;
910 }
911
912 static ssize_t
913 catia_listxattr(vfs_handle_struct *handle, const char *path,
914                 char *list, size_t size)
915 {
916         char *mapped_name = NULL;
917         NTSTATUS status;
918         ssize_t ret;
919
920         status = catia_string_replace_allocate(handle->conn,
921                                 path, &mapped_name, vfs_translate_to_unix);
922         if (!NT_STATUS_IS_OK(status)) {
923                 errno = map_errno_from_nt_status(status);
924                 return -1;
925         }
926
927
928         ret = SMB_VFS_NEXT_LISTXATTR(handle, mapped_name, list, size);
929         TALLOC_FREE(mapped_name);
930
931         return ret;
932 }
933
934 static int
935 catia_removexattr(vfs_handle_struct *handle, const char *path,
936                   const char *name)
937 {
938         char *mapped_name = NULL;
939         NTSTATUS status;
940         ssize_t ret;
941
942         status = catia_string_replace_allocate(handle->conn,
943                                 name, &mapped_name, vfs_translate_to_unix);
944         if (!NT_STATUS_IS_OK(status)) {
945                 errno = map_errno_from_nt_status(status);
946                 return -1;
947         }
948
949
950         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path, mapped_name);
951         TALLOC_FREE(mapped_name);
952
953         return ret;
954 }
955
956 static int
957 catia_setxattr(vfs_handle_struct *handle, const char *path,
958                const char *name, const void *value, size_t size,
959                int flags)
960 {
961         char *mapped_name = NULL;
962         NTSTATUS status;
963         ssize_t ret;
964
965         status = catia_string_replace_allocate(handle->conn,
966                                 name, &mapped_name, vfs_translate_to_unix);
967         if (!NT_STATUS_IS_OK(status)) {
968                 errno = map_errno_from_nt_status(status);
969                 return -1;
970         }
971
972
973         ret = SMB_VFS_NEXT_SETXATTR(handle, path, mapped_name, value, size, flags);
974         TALLOC_FREE(mapped_name);
975
976         return ret;
977 }
978
979 static struct vfs_fn_pointers vfs_catia_fns = {
980         .mkdir_fn = catia_mkdir,
981         .rmdir_fn = catia_rmdir,
982         .opendir_fn = catia_opendir,
983         .open_fn = catia_open,
984         .rename_fn = catia_rename,
985         .stat_fn = catia_stat,
986         .lstat_fn = catia_lstat,
987         .unlink_fn = catia_unlink,
988         .chown_fn = catia_chown,
989         .lchown_fn = catia_lchown,
990         .chmod_fn = catia_chmod,
991         .chdir_fn = catia_chdir,
992         .ntimes_fn = catia_ntimes,
993         .realpath_fn = catia_realpath,
994         .chflags_fn = catia_chflags,
995         .streaminfo_fn = catia_streaminfo,
996         .translate_name_fn = catia_translate_name,
997         .get_nt_acl_fn = catia_get_nt_acl,
998         .chmod_acl_fn = catia_chmod_acl,
999         .sys_acl_get_file_fn = catia_sys_acl_get_file,
1000         .sys_acl_set_file_fn = catia_sys_acl_set_file,
1001         .sys_acl_delete_def_file_fn = catia_sys_acl_delete_def_file,
1002         .getxattr_fn = catia_getxattr,
1003         .listxattr_fn = catia_listxattr,
1004         .removexattr_fn = catia_removexattr,
1005         .setxattr_fn = catia_setxattr,
1006 };
1007
1008 NTSTATUS vfs_catia_init(void)
1009 {
1010         NTSTATUS ret;
1011
1012         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "catia",
1013                                 &vfs_catia_fns);
1014         if (!NT_STATUS_IS_OK(ret))
1015                 return ret;
1016
1017         vfs_catia_debug_level = debug_add_class("catia");
1018         if (vfs_catia_debug_level == -1) {
1019                 vfs_catia_debug_level = DBGC_VFS;
1020                 DEBUG(0, ("vfs_catia: Couldn't register custom debugging "
1021                           "class!\n"));
1022         } else {
1023                 DEBUG(10, ("vfs_catia: Debug class number of "
1024                            "'catia': %d\n", vfs_catia_debug_level));
1025         }
1026
1027         return ret;
1028
1029 }