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