VFS: cap: Fixup cap_symlinkat() to cope with translating dirfsp path.
[samba.git] / source3 / modules / vfs_cap.c
1 /*
2  * CAP VFS module for Samba 3.x Version 0.3
3  *
4  * Copyright (C) Tim Potter, 1999-2000
5  * Copyright (C) Alexander Bokovoy, 2002-2003
6  * Copyright (C) Stefan (metze) Metzmacher, 2003
7  * Copyright (C) TAKAHASHI Motonobu (monyo), 2003
8  * Copyright (C) Jeremy Allison, 2007
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24
25 #include "includes.h"
26 #include "smbd/smbd.h"
27
28 /* cap functions */
29 static char *capencode(TALLOC_CTX *ctx, const char *from);
30 static char *capdecode(TALLOC_CTX *ctx, const char *from);
31
32 static uint64_t cap_disk_free(vfs_handle_struct *handle,
33                         const struct smb_filename *smb_fname,
34                         uint64_t *bsize,
35                         uint64_t *dfree,
36                         uint64_t *dsize)
37 {
38         char *capname = capencode(talloc_tos(), smb_fname->base_name);
39         struct smb_filename *cap_smb_fname = NULL;
40
41         if (!capname) {
42                 errno = ENOMEM;
43                 return (uint64_t)-1;
44         }
45         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
46                                         capname,
47                                         NULL,
48                                         NULL,
49                                         smb_fname->twrp,
50                                         smb_fname->flags);
51         if (cap_smb_fname == NULL) {
52                 TALLOC_FREE(capname);
53                 errno = ENOMEM;
54                 return (uint64_t)-1;
55         }
56         return SMB_VFS_NEXT_DISK_FREE(handle, cap_smb_fname,
57                         bsize, dfree, dsize);
58 }
59
60 static int cap_get_quota(vfs_handle_struct *handle,
61                         const struct smb_filename *smb_fname,
62                         enum SMB_QUOTA_TYPE qtype,
63                         unid_t id,
64                         SMB_DISK_QUOTA *dq)
65 {
66         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
67         struct smb_filename *cap_smb_fname = NULL;
68
69         if (!cappath) {
70                 errno = ENOMEM;
71                 return -1;
72         }
73         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
74                                         cappath,
75                                         NULL,
76                                         NULL,
77                                         smb_fname->twrp,
78                                         smb_fname->flags);
79         if (cap_smb_fname == NULL) {
80                 TALLOC_FREE(cappath);
81                 errno = ENOMEM;
82                 return -1;
83         }
84         return SMB_VFS_NEXT_GET_QUOTA(handle, cap_smb_fname, qtype, id, dq);
85 }
86
87 static struct dirent *cap_readdir(vfs_handle_struct *handle,
88                                   struct files_struct *dirfsp,
89                                   DIR *dirp,
90                                   SMB_STRUCT_STAT *sbuf)
91 {
92         struct dirent *result;
93         struct dirent *newdirent;
94         char *newname;
95         size_t newnamelen;
96         DEBUG(3,("cap: cap_readdir\n"));
97
98         result = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirp, NULL);
99         if (!result) {
100                 return NULL;
101         }
102
103         newname = capdecode(talloc_tos(), result->d_name);
104         if (!newname) {
105                 return NULL;
106         }
107         DEBUG(3,("cap: cap_readdir: %s\n", newname));
108         newnamelen = strlen(newname)+1;
109         newdirent = talloc_size(
110                 talloc_tos(), sizeof(struct dirent) + newnamelen);
111         if (!newdirent) {
112                 return NULL;
113         }
114         talloc_set_name_const(newdirent, "struct dirent");
115         memcpy(newdirent, result, sizeof(struct dirent));
116         memcpy(&newdirent->d_name, newname, newnamelen);
117         return newdirent;
118 }
119
120 static int cap_mkdirat(vfs_handle_struct *handle,
121                 struct files_struct *dirfsp,
122                 const struct smb_filename *smb_fname,
123                 mode_t mode)
124 {
125         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
126         struct smb_filename *cap_smb_fname = NULL;
127
128         if (!cappath) {
129                 errno = ENOMEM;
130                 return -1;
131         }
132
133         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
134                                         cappath,
135                                         NULL,
136                                         NULL,
137                                         smb_fname->twrp,
138                                         smb_fname->flags);
139         if (cap_smb_fname == NULL) {
140                 TALLOC_FREE(cappath);
141                 errno = ENOMEM;
142                 return -1;
143         }
144
145         return SMB_VFS_NEXT_MKDIRAT(handle,
146                         dirfsp,
147                         cap_smb_fname,
148                         mode);
149 }
150
151 static int cap_openat(vfs_handle_struct *handle,
152                       const struct files_struct *dirfsp,
153                       const struct smb_filename *smb_fname_in,
154                       files_struct *fsp,
155                       int flags,
156                       mode_t mode)
157 {
158         char *cappath = NULL;
159         struct smb_filename *smb_fname = NULL;
160         int ret;
161         int saved_errno = 0;
162
163         cappath = capencode(talloc_tos(), smb_fname_in->base_name);
164         if (cappath == NULL) {
165                 errno = ENOMEM;
166                 return -1;
167         }
168
169         smb_fname = cp_smb_filename(talloc_tos(), smb_fname_in);
170         if (smb_fname == NULL) {
171                 TALLOC_FREE(cappath);
172                 errno = ENOMEM;
173                 return -1;
174         }
175         smb_fname->base_name = cappath;
176
177         DBG_DEBUG("cap_open for %s\n", smb_fname_str_dbg(smb_fname));
178         ret = SMB_VFS_NEXT_OPENAT(handle,
179                                   dirfsp,
180                                   smb_fname,
181                                   fsp,
182                                   flags,
183                                   mode);
184
185         if (ret == -1) {
186                 saved_errno = errno;
187         }
188         TALLOC_FREE(cappath);
189         TALLOC_FREE(smb_fname);
190         if (saved_errno != 0) {
191                 errno = saved_errno;
192         }
193         return ret;
194 }
195
196 static int cap_renameat(vfs_handle_struct *handle,
197                         files_struct *srcfsp,
198                         const struct smb_filename *smb_fname_src,
199                         files_struct *dstfsp,
200                         const struct smb_filename *smb_fname_dst)
201 {
202         char *capold = NULL;
203         char *capnew = NULL;
204         struct smb_filename *smb_fname_src_tmp = NULL;
205         struct smb_filename *smb_fname_dst_tmp = NULL;
206         int ret = -1;
207
208         capold = capencode(talloc_tos(), smb_fname_src->base_name);
209         capnew = capencode(talloc_tos(), smb_fname_dst->base_name);
210         if (!capold || !capnew) {
211                 errno = ENOMEM;
212                 goto out;
213         }
214
215         /* Setup temporary smb_filename structs. */
216         smb_fname_src_tmp = cp_smb_filename(talloc_tos(), smb_fname_src);
217         if (smb_fname_src_tmp == NULL) {
218                 errno = ENOMEM;
219                 goto out;
220         }
221         smb_fname_dst_tmp = cp_smb_filename(talloc_tos(), smb_fname_dst);
222         if (smb_fname_dst_tmp == NULL) {
223                 errno = ENOMEM;
224                 goto out;
225         }
226
227         smb_fname_src_tmp->base_name = capold;
228         smb_fname_dst_tmp->base_name = capnew;
229
230         ret = SMB_VFS_NEXT_RENAMEAT(handle,
231                                 srcfsp,
232                                 smb_fname_src_tmp,
233                                 dstfsp,
234                                 smb_fname_dst_tmp);
235
236  out:
237         TALLOC_FREE(capold);
238         TALLOC_FREE(capnew);
239         TALLOC_FREE(smb_fname_src_tmp);
240         TALLOC_FREE(smb_fname_dst_tmp);
241
242         return ret;
243 }
244
245 static int cap_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
246 {
247         char *cappath;
248         char *tmp_base_name = NULL;
249         int ret;
250
251         cappath = capencode(talloc_tos(), smb_fname->base_name);
252
253         if (!cappath) {
254                 errno = ENOMEM;
255                 return -1;
256         }
257
258         tmp_base_name = smb_fname->base_name;
259         smb_fname->base_name = cappath;
260
261         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
262
263         smb_fname->base_name = tmp_base_name;
264         TALLOC_FREE(cappath);
265
266         return ret;
267 }
268
269 static int cap_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
270 {
271         char *cappath;
272         char *tmp_base_name = NULL;
273         int ret;
274
275         cappath = capencode(talloc_tos(), smb_fname->base_name);
276
277         if (!cappath) {
278                 errno = ENOMEM;
279                 return -1;
280         }
281
282         tmp_base_name = smb_fname->base_name;
283         smb_fname->base_name = cappath;
284
285         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
286
287         smb_fname->base_name = tmp_base_name;
288         TALLOC_FREE(cappath);
289
290         return ret;
291 }
292
293 static int cap_unlinkat(vfs_handle_struct *handle,
294                         struct files_struct *dirfsp,
295                         const struct smb_filename *smb_fname,
296                         int flags)
297 {
298         struct smb_filename *smb_fname_tmp = NULL;
299         char *cappath = NULL;
300         int ret;
301
302         cappath = capencode(talloc_tos(), smb_fname->base_name);
303         if (!cappath) {
304                 errno = ENOMEM;
305                 return -1;
306         }
307
308         /* Setup temporary smb_filename structs. */
309         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
310         if (smb_fname_tmp == NULL) {
311                 errno = ENOMEM;
312                 return -1;
313         }
314
315         smb_fname_tmp->base_name = cappath;
316
317         ret = SMB_VFS_NEXT_UNLINKAT(handle,
318                         dirfsp,
319                         smb_fname_tmp,
320                         flags);
321
322         TALLOC_FREE(smb_fname_tmp);
323         return ret;
324 }
325
326 static int cap_chmod(vfs_handle_struct *handle,
327                         const struct smb_filename *smb_fname,
328                         mode_t mode)
329 {
330         struct smb_filename *cap_smb_fname = NULL;
331         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
332         int ret;
333         int saved_errno;
334
335         if (!cappath) {
336                 errno = ENOMEM;
337                 return -1;
338         }
339
340         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
341                                         cappath,
342                                         NULL,
343                                         NULL,
344                                         smb_fname->twrp,
345                                         smb_fname->flags);
346         if (cap_smb_fname == NULL) {
347                 TALLOC_FREE(cappath);
348                 errno = ENOMEM;
349                 return -1;
350         }
351
352         ret = SMB_VFS_NEXT_CHMOD(handle, cap_smb_fname, mode);
353         saved_errno = errno;
354         TALLOC_FREE(cappath);
355         TALLOC_FREE(cap_smb_fname);
356         errno = saved_errno;
357         return ret;
358 }
359
360 static int cap_lchown(vfs_handle_struct *handle,
361                         const struct smb_filename *smb_fname,
362                         uid_t uid,
363                         gid_t gid)
364 {
365         struct smb_filename *cap_smb_fname = NULL;
366         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
367         int ret;
368         int saved_errno;
369
370         if (!cappath) {
371                 errno = ENOMEM;
372                 return -1;
373         }
374
375         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
376                                         cappath,
377                                         NULL,
378                                         NULL,
379                                         smb_fname->twrp,
380                                         smb_fname->flags);
381         if (cap_smb_fname == NULL) {
382                 TALLOC_FREE(cappath);
383                 errno = ENOMEM;
384                 return -1;
385         }
386
387         ret = SMB_VFS_NEXT_LCHOWN(handle, cap_smb_fname, uid, gid);
388         saved_errno = errno;
389         TALLOC_FREE(cappath);
390         TALLOC_FREE(cap_smb_fname);
391         errno = saved_errno;
392         return ret;
393 }
394
395 static int cap_chdir(vfs_handle_struct *handle,
396                         const struct smb_filename *smb_fname)
397 {
398         struct smb_filename *cap_smb_fname = NULL;
399         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
400         int ret;
401         int saved_errno = 0;
402
403         if (!cappath) {
404                 errno = ENOMEM;
405                 return -1;
406         }
407         DEBUG(3,("cap: cap_chdir for %s\n", smb_fname->base_name));
408
409         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
410                                         cappath,
411                                         NULL,
412                                         NULL,
413                                         smb_fname->twrp,
414                                         smb_fname->flags);
415         if (cap_smb_fname == NULL) {
416                 TALLOC_FREE(cappath);
417                 errno = ENOMEM;
418                 return -1;
419         }
420         ret = SMB_VFS_NEXT_CHDIR(handle, cap_smb_fname);
421         if (ret == -1) {
422                 saved_errno = errno;
423         }
424         TALLOC_FREE(cappath);
425         TALLOC_FREE(cap_smb_fname);
426         if (saved_errno != 0) {
427                 errno = saved_errno;
428         }
429         return ret;
430 }
431
432 static int cap_ntimes(vfs_handle_struct *handle,
433                       const struct smb_filename *smb_fname,
434                       struct smb_file_time *ft)
435 {
436         struct smb_filename *smb_fname_tmp = NULL;
437         char *cappath = NULL;
438         int ret;
439
440         cappath = capencode(talloc_tos(), smb_fname->base_name);
441
442         if (!cappath) {
443                 errno = ENOMEM;
444                 return -1;
445         }
446
447         /* Setup temporary smb_filename structs. */
448         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
449         if (smb_fname_tmp == NULL) {
450                 errno = ENOMEM;
451                 return -1;
452         }
453
454         smb_fname_tmp->base_name = cappath;
455
456         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
457
458         TALLOC_FREE(smb_fname_tmp);
459         return ret;
460 }
461
462 static int cap_symlinkat(vfs_handle_struct *handle,
463                         const struct smb_filename *link_contents,
464                         struct files_struct *dirfsp,
465                         const struct smb_filename *new_smb_fname)
466 {
467         struct smb_filename *full_fname = NULL;
468         char *capold = capencode(talloc_tos(), link_contents->base_name);
469         char *capnew = NULL;
470         struct smb_filename *new_link_target = NULL;
471         struct smb_filename *new_cap_smb_fname = NULL;
472         int saved_errno = 0;
473         int ret;
474
475         if (!capold || !capnew) {
476                 errno = ENOMEM;
477                 return -1;
478         }
479
480         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
481                                                 dirfsp,
482                                                 new_smb_fname);
483         if (full_fname == NULL) {
484                 return -1;
485         }
486
487         capnew = capencode(talloc_tos(), full_fname->base_name);
488         if (!capnew) {
489                 TALLOC_FREE(full_fname);
490                 errno = ENOMEM;
491                 return -1;
492         }
493
494         new_link_target = synthetic_smb_fname(talloc_tos(),
495                                               capold,
496                                               NULL,
497                                               NULL,
498                                               new_smb_fname->twrp,
499                                               new_smb_fname->flags);
500         if (new_link_target == NULL) {
501                 TALLOC_FREE(full_fname);
502                 TALLOC_FREE(capold);
503                 TALLOC_FREE(capnew);
504                 errno = ENOMEM;
505                 return -1;
506         }
507
508         new_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
509                                         capnew,
510                                         NULL,
511                                         NULL,
512                                         new_smb_fname->twrp,
513                                         new_smb_fname->flags);
514         if (new_cap_smb_fname == NULL) {
515                 TALLOC_FREE(full_fname);
516                 TALLOC_FREE(capold);
517                 TALLOC_FREE(capnew);
518                 TALLOC_FREE(new_link_target);
519                 errno = ENOMEM;
520                 return -1;
521         }
522         ret = SMB_VFS_NEXT_SYMLINKAT(handle,
523                         new_link_target,
524                         handle->conn->cwd_fsp,
525                         new_cap_smb_fname);
526         if (ret == -1) {
527                 saved_errno = errno;
528         }
529         TALLOC_FREE(full_fname);
530         TALLOC_FREE(capold);
531         TALLOC_FREE(capnew);
532         TALLOC_FREE(new_link_target);
533         TALLOC_FREE(new_cap_smb_fname);
534         if (saved_errno != 0) {
535                 errno = saved_errno;
536         }
537         return ret;
538 }
539
540 static int cap_readlinkat(vfs_handle_struct *handle,
541                         const struct files_struct *dirfsp,
542                         const struct smb_filename *smb_fname,
543                         char *buf,
544                         size_t bufsiz)
545 {
546         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
547         struct smb_filename *cap_smb_fname = NULL;
548         int saved_errno = 0;
549         int ret;
550
551         if (!cappath) {
552                 errno = ENOMEM;
553                 return -1;
554         }
555         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
556                                         cappath,
557                                         NULL,
558                                         NULL,
559                                         smb_fname->twrp,
560                                         smb_fname->flags);
561         if (cap_smb_fname == NULL) {
562                 TALLOC_FREE(cappath);
563                 errno = ENOMEM;
564                 return -1;
565         }
566         ret = SMB_VFS_NEXT_READLINKAT(handle,
567                         dirfsp,
568                         cap_smb_fname,
569                         buf,
570                         bufsiz);
571         if (ret == -1) {
572                 saved_errno = errno;
573         }
574         TALLOC_FREE(cappath);
575         TALLOC_FREE(cap_smb_fname);
576         if (saved_errno != 0) {
577                 errno = saved_errno;
578         }
579         return ret;
580 }
581
582 static int cap_linkat(vfs_handle_struct *handle,
583                 files_struct *srcfsp,
584                 const struct smb_filename *old_smb_fname,
585                 files_struct *dstfsp,
586                 const struct smb_filename *new_smb_fname,
587                 int flags)
588 {
589         char *capold = capencode(talloc_tos(), old_smb_fname->base_name);
590         char *capnew = capencode(talloc_tos(), new_smb_fname->base_name);
591         struct smb_filename *old_cap_smb_fname = NULL;
592         struct smb_filename *new_cap_smb_fname = NULL;
593         int saved_errno = 0;
594         int ret;
595
596         if (!capold || !capnew) {
597                 errno = ENOMEM;
598                 return -1;
599         }
600         old_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
601                                         capold,
602                                         NULL,
603                                         NULL,
604                                         old_smb_fname->twrp,
605                                         old_smb_fname->flags);
606         if (old_cap_smb_fname == NULL) {
607                 TALLOC_FREE(capold);
608                 TALLOC_FREE(capnew);
609                 errno = ENOMEM;
610                 return -1;
611         }
612         new_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
613                                         capnew,
614                                         NULL,
615                                         NULL,
616                                         new_smb_fname->twrp,
617                                         new_smb_fname->flags);
618         if (new_cap_smb_fname == NULL) {
619                 TALLOC_FREE(capold);
620                 TALLOC_FREE(capnew);
621                 TALLOC_FREE(old_cap_smb_fname);
622                 errno = ENOMEM;
623                 return -1;
624         }
625         ret = SMB_VFS_NEXT_LINKAT(handle,
626                         srcfsp,
627                         old_cap_smb_fname,
628                         dstfsp,
629                         new_cap_smb_fname,
630                         flags);
631         if (ret == -1) {
632                 saved_errno = errno;
633         }
634         TALLOC_FREE(capold);
635         TALLOC_FREE(capnew);
636         TALLOC_FREE(old_cap_smb_fname);
637         TALLOC_FREE(new_cap_smb_fname);
638         if (saved_errno != 0) {
639                 errno = saved_errno;
640         }
641         return ret;
642 }
643
644 static int cap_mknodat(vfs_handle_struct *handle,
645                 files_struct *dirfsp,
646                 const struct smb_filename *smb_fname,
647                 mode_t mode,
648                 SMB_DEV_T dev)
649 {
650         struct smb_filename *full_fname = NULL;
651         struct smb_filename *cap_smb_fname = NULL;
652         char *cappath = NULL;
653         int ret;
654         int saved_errno = 0;
655
656         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
657                                                 dirfsp,
658                                                 smb_fname);
659         if (full_fname == NULL) {
660                 return -1;
661         }
662
663         cappath = capencode(talloc_tos(), full_fname->base_name);
664         if (!cappath) {
665                 TALLOC_FREE(full_fname);
666                 errno = ENOMEM;
667                 return -1;
668         }
669         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
670                                         cappath,
671                                         NULL,
672                                         NULL,
673                                         smb_fname->twrp,
674                                         smb_fname->flags);
675         if (cap_smb_fname == NULL) {
676                 TALLOC_FREE(full_fname);
677                 TALLOC_FREE(cappath);
678                 errno = ENOMEM;
679                 return -1;
680         }
681         ret = SMB_VFS_NEXT_MKNODAT(handle,
682                         handle->conn->cwd_fsp,
683                         cap_smb_fname,
684                         mode,
685                         dev);
686         if (ret == -1) {
687                 saved_errno = errno;
688         }
689         TALLOC_FREE(full_fname);
690         TALLOC_FREE(cappath);
691         TALLOC_FREE(cap_smb_fname);
692         if (saved_errno != 0) {
693                 errno = saved_errno;
694         }
695         return ret;
696 }
697
698 static struct smb_filename *cap_realpath(vfs_handle_struct *handle,
699                         TALLOC_CTX *ctx,
700                         const struct smb_filename *smb_fname)
701 {
702         /* monyo need capencode'ed and capdecode'ed? */
703         struct smb_filename *cap_smb_fname = NULL;
704         struct smb_filename *return_fname = NULL;
705         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
706         int saved_errno = 0;
707
708         if (!cappath) {
709                 errno = ENOMEM;
710                 return NULL;
711         }
712         cap_smb_fname = synthetic_smb_fname(ctx,
713                                         cappath,
714                                         NULL,
715                                         NULL,
716                                         smb_fname->twrp,
717                                         smb_fname->flags);
718         if (cap_smb_fname == NULL) {
719                 TALLOC_FREE(cappath);
720                 errno = ENOMEM;
721                 return NULL;
722         }
723         return_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, cap_smb_fname);
724         if (return_fname == NULL) {
725                 saved_errno = errno;
726         }
727         TALLOC_FREE(cappath);
728         TALLOC_FREE(cap_smb_fname);
729         if (saved_errno != 0) {
730                 errno = saved_errno;
731         }
732         return return_fname;
733 }
734
735 static SMB_ACL_T cap_sys_acl_get_file(vfs_handle_struct *handle,
736                                 const struct smb_filename *smb_fname,
737                                 SMB_ACL_TYPE_T type,
738                                 TALLOC_CTX *mem_ctx)
739 {
740         struct smb_filename *cap_smb_fname = NULL;
741         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
742         SMB_ACL_T ret;
743         int saved_errno = 0;
744
745         if (!cappath) {
746                 errno = ENOMEM;
747                 return (SMB_ACL_T)NULL;
748         }
749         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
750                                         cappath,
751                                         NULL,
752                                         NULL,
753                                         smb_fname->twrp,
754                                         smb_fname->flags);
755         if (cap_smb_fname == NULL) {
756                 TALLOC_FREE(cappath);
757                 errno = ENOMEM;
758                 return (SMB_ACL_T)NULL;
759         }
760         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, cap_smb_fname,
761                                 type, mem_ctx);
762         if (ret == NULL) {
763                 saved_errno = errno;
764         }
765         TALLOC_FREE(cappath);
766         TALLOC_FREE(cap_smb_fname);
767         if (saved_errno != 0) {
768                 errno = saved_errno;
769         }
770         return ret;
771 }
772
773 static int cap_sys_acl_delete_def_file(vfs_handle_struct *handle,
774                         const struct smb_filename *smb_fname)
775 {
776         struct smb_filename *cap_smb_fname = NULL;
777         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
778         int ret;
779         int saved_errno = 0;
780
781         if (!cappath) {
782                 errno = ENOMEM;
783                 return -1;
784         }
785         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
786                                         cappath,
787                                         NULL,
788                                         NULL,
789                                         smb_fname->twrp,
790                                         smb_fname->flags);
791         if (cap_smb_fname == NULL) {
792                 TALLOC_FREE(cappath);
793                 errno = ENOMEM;
794                 return -1;
795         }
796         ret = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, cap_smb_fname);
797         if (ret == -1) {
798                 saved_errno = errno;
799         }
800         TALLOC_FREE(cappath);
801         TALLOC_FREE(cap_smb_fname);
802         if (saved_errno) {
803                 errno = saved_errno;
804         }
805         return ret;
806 }
807
808 static ssize_t cap_getxattr(vfs_handle_struct *handle,
809                         const struct smb_filename *smb_fname,
810                         const char *name,
811                         void *value,
812                         size_t size)
813 {
814         struct smb_filename *cap_smb_fname = NULL;
815         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
816         char *capname = capencode(talloc_tos(), name);
817         ssize_t ret;
818         int saved_errno = 0;
819
820         if (!cappath || !capname) {
821                 errno = ENOMEM;
822                 return -1;
823         }
824         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
825                                         cappath,
826                                         NULL,
827                                         NULL,
828                                         smb_fname->twrp,
829                                         smb_fname->flags);
830         if (cap_smb_fname == NULL) {
831                 TALLOC_FREE(cappath);
832                 TALLOC_FREE(capname);
833                 errno = ENOMEM;
834                 return -1;
835         }
836         ret = SMB_VFS_NEXT_GETXATTR(handle, cap_smb_fname,
837                         capname, value, size);
838         if (ret == -1) {
839                 saved_errno = errno;
840         }
841         TALLOC_FREE(cappath);
842         TALLOC_FREE(capname);
843         TALLOC_FREE(cap_smb_fname);
844         if (saved_errno) {
845                 errno = saved_errno;
846         }
847         return ret;
848 }
849
850 static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
851 {
852         char *cappath = capencode(talloc_tos(), path);
853
854         if (!cappath) {
855                 errno = ENOMEM;
856                 return -1;
857         }
858         return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
859 }
860
861 static ssize_t cap_listxattr(vfs_handle_struct *handle,
862                                 const struct smb_filename *smb_fname,
863                                 char *list,
864                                 size_t size)
865 {
866         struct smb_filename *cap_smb_fname = NULL;
867         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
868         ssize_t ret;
869         int saved_errno = 0;
870
871         if (!cappath) {
872                 errno = ENOMEM;
873                 return -1;
874         }
875         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
876                                         cappath,
877                                         NULL,
878                                         NULL,
879                                         smb_fname->twrp,
880                                         smb_fname->flags);
881         if (cap_smb_fname == NULL) {
882                 TALLOC_FREE(cappath);
883                 errno = ENOMEM;
884                 return -1;
885         }
886         ret = SMB_VFS_NEXT_LISTXATTR(handle, cap_smb_fname, list, size);
887         if (ret == -1) {
888                 saved_errno = errno;
889         }
890         TALLOC_FREE(cappath);
891         TALLOC_FREE(cap_smb_fname);
892         if (saved_errno) {
893                 errno = saved_errno;
894         }
895         return ret;
896 }
897
898 static int cap_removexattr(vfs_handle_struct *handle,
899                                 const struct smb_filename *smb_fname,
900                                 const char *name)
901 {
902         struct smb_filename *cap_smb_fname = NULL;
903         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
904         char *capname = capencode(talloc_tos(), name);
905         int ret;
906         int saved_errno = 0;
907
908         if (!cappath || !capname) {
909                 errno = ENOMEM;
910                 return -1;
911         }
912         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
913                                         cappath,
914                                         NULL,
915                                         NULL,
916                                         smb_fname->twrp,
917                                         smb_fname->flags);
918         if (cap_smb_fname == NULL) {
919                 TALLOC_FREE(cappath);
920                 TALLOC_FREE(capname);
921                 errno = ENOMEM;
922                 return -1;
923         }
924         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, cap_smb_fname, capname);
925         if (ret == -1) {
926                 saved_errno = errno;
927         }
928         TALLOC_FREE(cappath);
929         TALLOC_FREE(capname);
930         TALLOC_FREE(cap_smb_fname);
931         if (saved_errno) {
932                 errno = saved_errno;
933         }
934         return ret;
935 }
936
937 static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
938 {
939         char *cappath = capencode(talloc_tos(), path);
940
941         if (!cappath) {
942                 errno = ENOMEM;
943                 return -1;
944         }
945         return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
946 }
947
948 static int cap_setxattr(vfs_handle_struct *handle,
949                         const struct smb_filename *smb_fname,
950                         const char *name,
951                         const void *value,
952                         size_t size,
953                         int flags)
954 {
955         struct smb_filename *cap_smb_fname = NULL;
956         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
957         char *capname = capencode(talloc_tos(), name);
958         int ret;
959         int saved_errno = 0;
960
961         if (!cappath || !capname) {
962                 errno = ENOMEM;
963                 return -1;
964         }
965         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
966                                         cappath,
967                                         NULL,
968                                         NULL,
969                                         smb_fname->twrp,
970                                         smb_fname->flags);
971         if (cap_smb_fname == NULL) {
972                 TALLOC_FREE(cappath);
973                 TALLOC_FREE(capname);
974                 errno = ENOMEM;
975                 return -1;
976         }
977         ret = SMB_VFS_NEXT_SETXATTR(handle, cap_smb_fname,
978                                 capname, value, size, flags);
979         if (ret == -1) {
980                 saved_errno = errno;
981         }
982         TALLOC_FREE(cappath);
983         TALLOC_FREE(capname);
984         TALLOC_FREE(cap_smb_fname);
985         if (saved_errno) {
986                 errno = saved_errno;
987         }
988         return ret;
989 }
990
991 static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
992 {
993         char *cappath = capencode(talloc_tos(), path);
994
995         if (!cappath) {
996                 errno = ENOMEM;
997                 return -1;
998         }
999         return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
1000 }
1001
1002 static NTSTATUS cap_create_dfs_pathat(vfs_handle_struct *handle,
1003                         files_struct *dirfsp,
1004                         const struct smb_filename *smb_fname,
1005                         const struct referral *reflist,
1006                         size_t referral_count)
1007 {
1008         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
1009         struct smb_filename *cap_smb_fname = NULL;
1010         NTSTATUS status;
1011
1012         if (cappath == NULL) {
1013                 return NT_STATUS_NO_MEMORY;
1014         }
1015         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
1016                                         cappath,
1017                                         NULL,
1018                                         NULL,
1019                                         smb_fname->twrp,
1020                                         smb_fname->flags);
1021         if (cap_smb_fname == NULL) {
1022                 TALLOC_FREE(cappath);
1023                 return NT_STATUS_NO_MEMORY;
1024         }
1025         status = SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
1026                         dirfsp,
1027                         cap_smb_fname,
1028                         reflist,
1029                         referral_count);
1030         TALLOC_FREE(cappath);
1031         TALLOC_FREE(cap_smb_fname);
1032         return status;
1033 }
1034
1035 static NTSTATUS cap_read_dfs_pathat(struct vfs_handle_struct *handle,
1036                         TALLOC_CTX *mem_ctx,
1037                         struct files_struct *dirfsp,
1038                         struct smb_filename *smb_fname,
1039                         struct referral **ppreflist,
1040                         size_t *preferral_count)
1041 {
1042         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
1043         struct smb_filename *cap_smb_fname = NULL;
1044         NTSTATUS status;
1045
1046         if (cappath == NULL) {
1047                 return NT_STATUS_NO_MEMORY;
1048         }
1049         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
1050                                 cappath,
1051                                 NULL,
1052                                 NULL,
1053                                 smb_fname->twrp,
1054                                 smb_fname->flags);
1055         if (cap_smb_fname == NULL) {
1056                 TALLOC_FREE(cappath);
1057                 return NT_STATUS_NO_MEMORY;
1058         }
1059
1060         status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
1061                         mem_ctx,
1062                         dirfsp,
1063                         cap_smb_fname,
1064                         ppreflist,
1065                         preferral_count);
1066
1067         if (NT_STATUS_IS_OK(status)) {
1068                 /* Return any stat(2) info. */
1069                 smb_fname->st = cap_smb_fname->st;
1070         }
1071
1072         TALLOC_FREE(cappath);
1073         TALLOC_FREE(cap_smb_fname);
1074         return status;
1075 }
1076
1077 static struct vfs_fn_pointers vfs_cap_fns = {
1078         .disk_free_fn = cap_disk_free,
1079         .get_quota_fn = cap_get_quota,
1080         .readdir_fn = cap_readdir,
1081         .mkdirat_fn = cap_mkdirat,
1082         .openat_fn = cap_openat,
1083         .renameat_fn = cap_renameat,
1084         .stat_fn = cap_stat,
1085         .lstat_fn = cap_lstat,
1086         .unlinkat_fn = cap_unlinkat,
1087         .chmod_fn = cap_chmod,
1088         .lchown_fn = cap_lchown,
1089         .chdir_fn = cap_chdir,
1090         .ntimes_fn = cap_ntimes,
1091         .symlinkat_fn = cap_symlinkat,
1092         .readlinkat_fn = cap_readlinkat,
1093         .linkat_fn = cap_linkat,
1094         .mknodat_fn = cap_mknodat,
1095         .realpath_fn = cap_realpath,
1096         .sys_acl_get_file_fn = cap_sys_acl_get_file,
1097         .sys_acl_delete_def_file_fn = cap_sys_acl_delete_def_file,
1098         .getxattr_fn = cap_getxattr,
1099         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1100         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1101         .fgetxattr_fn = cap_fgetxattr,
1102         .listxattr_fn = cap_listxattr,
1103         .removexattr_fn = cap_removexattr,
1104         .fremovexattr_fn = cap_fremovexattr,
1105         .setxattr_fn = cap_setxattr,
1106         .fsetxattr_fn = cap_fsetxattr,
1107         .create_dfs_pathat_fn = cap_create_dfs_pathat,
1108         .read_dfs_pathat_fn = cap_read_dfs_pathat
1109 };
1110
1111 static_decl_vfs;
1112 NTSTATUS vfs_cap_init(TALLOC_CTX *ctx)
1113 {
1114         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "cap",
1115                                 &vfs_cap_fns);
1116 }
1117
1118 /* For CAP functions */
1119 #define hex_tag ':'
1120 #define hex2bin(c)              hex2bin_table[(unsigned char)(c)]
1121 #define bin2hex(c)              bin2hex_table[(unsigned char)(c)]
1122 #define is_hex(s)               ((s)[0] == hex_tag)
1123
1124 static unsigned char hex2bin_table[256] = {
1125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
1126 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
1127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1128 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
1129 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x40 */
1130 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
1131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1132 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x60 */
1133 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
1134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
1135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */
1136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */
1137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */
1138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */
1139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */
1140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */
1141 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */
1142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 */
1143 };
1144 static unsigned char bin2hex_table[256] = "0123456789abcdef";
1145
1146 /*******************************************************************
1147   original code -> ":xx"  - CAP format
1148 ********************************************************************/
1149
1150 static char *capencode(TALLOC_CTX *ctx, const char *from)
1151 {
1152         char *out = NULL;
1153         const char *p1;
1154         char *to = NULL;
1155         size_t len = 0;
1156
1157         for (p1 = from; *p1; p1++) {
1158                 if ((unsigned char)*p1 >= 0x80) {
1159                         len += 3;
1160                 } else {
1161                         len++;
1162                 }
1163         }
1164         len++;
1165
1166         to = talloc_array(ctx, char, len);
1167         if (!to) {
1168                 return NULL;
1169         }
1170
1171         for (out = to; *from;) {
1172                 /* buffer husoku error */
1173                 if ((unsigned char)*from >= 0x80) {
1174                         *out++ = hex_tag;
1175                         *out++ = bin2hex (((*from)>>4)&0x0f);
1176                         *out++ = bin2hex ((*from)&0x0f);
1177                         from++;
1178                 } else {
1179                         *out++ = *from++;
1180                 }
1181         }
1182         *out = '\0';
1183         return to;
1184 }
1185
1186 /*******************************************************************
1187   CAP -> original code
1188 ********************************************************************/
1189 /* ":xx" -> a byte */
1190
1191 static char *capdecode(TALLOC_CTX *ctx, const char *from)
1192 {
1193         const char *p1;
1194         char *out = NULL;
1195         char *to = NULL;
1196         size_t len = 0;
1197
1198         for (p1 = from; *p1; len++) {
1199                 if (is_hex(p1)) {
1200                         p1 += 3;
1201                 } else {
1202                         p1++;
1203                 }
1204         }
1205         len++;
1206
1207         to = talloc_array(ctx, char, len);
1208         if (!to) {
1209                 return NULL;
1210         }
1211
1212         for (out = to; *from;) {
1213                 if (is_hex(from)) {
1214                         *out++ = (hex2bin(from[1])<<4) | (hex2bin(from[2]));
1215                         from += 3;
1216                 } else {
1217                         *out++ = *from++;
1218                 }
1219         }
1220         *out = '\0';
1221         return to;
1222 }