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