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