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