05c5426919cc9affcb967cc4d6492b616d5a79fe
[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_renameat(vfs_handle_struct *handle,
220                         files_struct *srcfsp,
221                         const struct smb_filename *smb_fname_src,
222                         files_struct *dstfsp,
223                         const struct smb_filename *smb_fname_dst)
224 {
225         char *capold = NULL;
226         char *capnew = NULL;
227         struct smb_filename *smb_fname_src_tmp = NULL;
228         struct smb_filename *smb_fname_dst_tmp = NULL;
229         int ret = -1;
230
231         capold = capencode(talloc_tos(), smb_fname_src->base_name);
232         capnew = capencode(talloc_tos(), smb_fname_dst->base_name);
233         if (!capold || !capnew) {
234                 errno = ENOMEM;
235                 goto out;
236         }
237
238         /* Setup temporary smb_filename structs. */
239         smb_fname_src_tmp = cp_smb_filename(talloc_tos(), smb_fname_src);
240         if (smb_fname_src_tmp == NULL) {
241                 errno = ENOMEM;
242                 goto out;
243         }
244         smb_fname_dst_tmp = cp_smb_filename(talloc_tos(), smb_fname_dst);
245         if (smb_fname_dst_tmp == NULL) {
246                 errno = ENOMEM;
247                 goto out;
248         }
249
250         smb_fname_src_tmp->base_name = capold;
251         smb_fname_dst_tmp->base_name = capnew;
252
253         ret = SMB_VFS_NEXT_RENAMEAT(handle,
254                                 srcfsp,
255                                 smb_fname_src_tmp,
256                                 dstfsp,
257                                 smb_fname_dst_tmp);
258
259  out:
260         TALLOC_FREE(capold);
261         TALLOC_FREE(capnew);
262         TALLOC_FREE(smb_fname_src_tmp);
263         TALLOC_FREE(smb_fname_dst_tmp);
264
265         return ret;
266 }
267
268 static int cap_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
269 {
270         char *cappath;
271         char *tmp_base_name = NULL;
272         int ret;
273
274         cappath = capencode(talloc_tos(), smb_fname->base_name);
275
276         if (!cappath) {
277                 errno = ENOMEM;
278                 return -1;
279         }
280
281         tmp_base_name = smb_fname->base_name;
282         smb_fname->base_name = cappath;
283
284         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
285
286         smb_fname->base_name = tmp_base_name;
287         TALLOC_FREE(cappath);
288
289         return ret;
290 }
291
292 static int cap_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
293 {
294         char *cappath;
295         char *tmp_base_name = NULL;
296         int ret;
297
298         cappath = capencode(talloc_tos(), smb_fname->base_name);
299
300         if (!cappath) {
301                 errno = ENOMEM;
302                 return -1;
303         }
304
305         tmp_base_name = smb_fname->base_name;
306         smb_fname->base_name = cappath;
307
308         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
309
310         smb_fname->base_name = tmp_base_name;
311         TALLOC_FREE(cappath);
312
313         return ret;
314 }
315
316 static int cap_unlink(vfs_handle_struct *handle,
317                       const struct smb_filename *smb_fname)
318 {
319         struct smb_filename *smb_fname_tmp = NULL;
320         char *cappath = NULL;
321         int ret;
322
323         cappath = capencode(talloc_tos(), smb_fname->base_name);
324         if (!cappath) {
325                 errno = ENOMEM;
326                 return -1;
327         }
328
329         /* Setup temporary smb_filename structs. */
330         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
331         if (smb_fname_tmp == NULL) {
332                 errno = ENOMEM;
333                 return -1;
334         }
335
336         smb_fname_tmp->base_name = cappath;
337
338         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
339
340         TALLOC_FREE(smb_fname_tmp);
341         return ret;
342 }
343
344 static int cap_chmod(vfs_handle_struct *handle,
345                         const struct smb_filename *smb_fname,
346                         mode_t mode)
347 {
348         struct smb_filename *cap_smb_fname = NULL;
349         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
350         int ret;
351         int saved_errno;
352
353         if (!cappath) {
354                 errno = ENOMEM;
355                 return -1;
356         }
357
358         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
359                                         cappath,
360                                         NULL,
361                                         NULL,
362                                         smb_fname->flags);
363         if (cap_smb_fname == NULL) {
364                 TALLOC_FREE(cappath);
365                 errno = ENOMEM;
366                 return -1;
367         }
368
369         ret = SMB_VFS_NEXT_CHMOD(handle, cap_smb_fname, mode);
370         saved_errno = errno;
371         TALLOC_FREE(cappath);
372         TALLOC_FREE(cap_smb_fname);
373         errno = saved_errno;
374         return ret;
375 }
376
377 static int cap_chown(vfs_handle_struct *handle,
378                         const struct smb_filename *smb_fname,
379                         uid_t uid,
380                         gid_t gid)
381 {
382         struct smb_filename *cap_smb_fname = NULL;
383         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
384         int ret;
385         int saved_errno;
386
387         if (!cappath) {
388                 errno = ENOMEM;
389                 return -1;
390         }
391
392         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
393                                         cappath,
394                                         NULL,
395                                         NULL,
396                                         smb_fname->flags);
397         if (cap_smb_fname == NULL) {
398                 TALLOC_FREE(cappath);
399                 errno = ENOMEM;
400                 return -1;
401         }
402
403         ret = SMB_VFS_NEXT_CHOWN(handle, cap_smb_fname, uid, gid);
404         saved_errno = errno;
405         TALLOC_FREE(cappath);
406         TALLOC_FREE(cap_smb_fname);
407         errno = saved_errno;
408         return ret;
409 }
410
411 static int cap_lchown(vfs_handle_struct *handle,
412                         const struct smb_filename *smb_fname,
413                         uid_t uid,
414                         gid_t gid)
415 {
416         struct smb_filename *cap_smb_fname = NULL;
417         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
418         int ret;
419         int saved_errno;
420
421         if (!cappath) {
422                 errno = ENOMEM;
423                 return -1;
424         }
425
426         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
427                                         cappath,
428                                         NULL,
429                                         NULL,
430                                         smb_fname->flags);
431         if (cap_smb_fname == NULL) {
432                 TALLOC_FREE(cappath);
433                 errno = ENOMEM;
434                 return -1;
435         }
436
437         ret = SMB_VFS_NEXT_LCHOWN(handle, cap_smb_fname, uid, gid);
438         saved_errno = errno;
439         TALLOC_FREE(cappath);
440         TALLOC_FREE(cap_smb_fname);
441         errno = saved_errno;
442         return ret;
443 }
444
445 static int cap_chdir(vfs_handle_struct *handle,
446                         const struct smb_filename *smb_fname)
447 {
448         struct smb_filename *cap_smb_fname = NULL;
449         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
450         int ret;
451         int saved_errno = 0;
452
453         if (!cappath) {
454                 errno = ENOMEM;
455                 return -1;
456         }
457         DEBUG(3,("cap: cap_chdir for %s\n", smb_fname->base_name));
458
459         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
460                                         cappath,
461                                         NULL,
462                                         NULL,
463                                         smb_fname->flags);
464         if (cap_smb_fname == NULL) {
465                 TALLOC_FREE(cappath);
466                 errno = ENOMEM;
467                 return -1;
468         }
469         ret = SMB_VFS_NEXT_CHDIR(handle, cap_smb_fname);
470         if (ret == -1) {
471                 saved_errno = errno;
472         }
473         TALLOC_FREE(cappath);
474         TALLOC_FREE(cap_smb_fname);
475         if (saved_errno != 0) {
476                 errno = saved_errno;
477         }
478         return ret;
479 }
480
481 static int cap_ntimes(vfs_handle_struct *handle,
482                       const struct smb_filename *smb_fname,
483                       struct smb_file_time *ft)
484 {
485         struct smb_filename *smb_fname_tmp = NULL;
486         char *cappath = NULL;
487         int ret;
488
489         cappath = capencode(talloc_tos(), smb_fname->base_name);
490
491         if (!cappath) {
492                 errno = ENOMEM;
493                 return -1;
494         }
495
496         /* Setup temporary smb_filename structs. */
497         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
498         if (smb_fname_tmp == NULL) {
499                 errno = ENOMEM;
500                 return -1;
501         }
502
503         smb_fname_tmp->base_name = cappath;
504
505         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
506
507         TALLOC_FREE(smb_fname_tmp);
508         return ret;
509 }
510
511
512 static int cap_symlink(vfs_handle_struct *handle,
513                         const char *link_contents,
514                         const struct smb_filename *new_smb_fname)
515 {
516         char *capold = capencode(talloc_tos(), link_contents);
517         char *capnew = capencode(talloc_tos(), new_smb_fname->base_name);
518         struct smb_filename *new_cap_smb_fname = NULL;
519         int saved_errno = 0;
520         int ret;
521
522         if (!capold || !capnew) {
523                 errno = ENOMEM;
524                 return -1;
525         }
526         new_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
527                                         capnew,
528                                         NULL,
529                                         NULL,
530                                         new_smb_fname->flags);
531         if (new_cap_smb_fname == NULL) {
532                 TALLOC_FREE(capold);
533                 TALLOC_FREE(capnew);
534                 errno = ENOMEM;
535                 return -1;
536         }
537         ret = SMB_VFS_NEXT_SYMLINK(handle,
538                         capold,
539                         new_cap_smb_fname);
540         if (ret == -1) {
541                 saved_errno = errno;
542         }
543         TALLOC_FREE(capold);
544         TALLOC_FREE(capnew);
545         TALLOC_FREE(new_cap_smb_fname);
546         if (saved_errno != 0) {
547                 errno = saved_errno;
548         }
549         return ret;
550 }
551
552 static int cap_readlink(vfs_handle_struct *handle,
553                         const struct smb_filename *smb_fname,
554                         char *buf,
555                         size_t bufsiz)
556 {
557         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
558         struct smb_filename *cap_smb_fname = NULL;
559         int saved_errno = 0;
560         int ret;
561
562         if (!cappath) {
563                 errno = ENOMEM;
564                 return -1;
565         }
566         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
567                                         cappath,
568                                         NULL,
569                                         NULL,
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_READLINK(handle, cap_smb_fname, buf, bufsiz);
577         if (ret == -1) {
578                 saved_errno = errno;
579         }
580         TALLOC_FREE(cappath);
581         TALLOC_FREE(cap_smb_fname);
582         if (saved_errno != 0) {
583                 errno = saved_errno;
584         }
585         return ret;
586 }
587
588 static int cap_linkat(vfs_handle_struct *handle,
589                 files_struct *srcfsp,
590                 const struct smb_filename *old_smb_fname,
591                 files_struct *dstfsp,
592                 const struct smb_filename *new_smb_fname,
593                 int flags)
594 {
595         char *capold = capencode(talloc_tos(), old_smb_fname->base_name);
596         char *capnew = capencode(talloc_tos(), new_smb_fname->base_name);
597         struct smb_filename *old_cap_smb_fname = NULL;
598         struct smb_filename *new_cap_smb_fname = NULL;
599         int saved_errno = 0;
600         int ret;
601
602         if (!capold || !capnew) {
603                 errno = ENOMEM;
604                 return -1;
605         }
606         old_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
607                                         capold,
608                                         NULL,
609                                         NULL,
610                                         old_smb_fname->flags);
611         if (old_cap_smb_fname == NULL) {
612                 TALLOC_FREE(capold);
613                 TALLOC_FREE(capnew);
614                 errno = ENOMEM;
615                 return -1;
616         }
617         new_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
618                                         capnew,
619                                         NULL,
620                                         NULL,
621                                         new_smb_fname->flags);
622         if (new_cap_smb_fname == NULL) {
623                 TALLOC_FREE(capold);
624                 TALLOC_FREE(capnew);
625                 TALLOC_FREE(old_cap_smb_fname);
626                 errno = ENOMEM;
627                 return -1;
628         }
629         ret = SMB_VFS_NEXT_LINKAT(handle,
630                         srcfsp,
631                         old_cap_smb_fname,
632                         dstfsp,
633                         new_cap_smb_fname,
634                         flags);
635         if (ret == -1) {
636                 saved_errno = errno;
637         }
638         TALLOC_FREE(capold);
639         TALLOC_FREE(capnew);
640         TALLOC_FREE(old_cap_smb_fname);
641         TALLOC_FREE(new_cap_smb_fname);
642         if (saved_errno != 0) {
643                 errno = saved_errno;
644         }
645         return ret;
646 }
647
648 static int cap_mknod(vfs_handle_struct *handle,
649                 const struct smb_filename *smb_fname,
650                 mode_t mode,
651                 SMB_DEV_T dev)
652 {
653         struct smb_filename *cap_smb_fname = NULL;
654         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
655         int ret;
656         int saved_errno = 0;
657
658         if (!cappath) {
659                 errno = ENOMEM;
660                 return -1;
661         }
662         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
663                                         cappath,
664                                         NULL,
665                                         NULL,
666                                         smb_fname->flags);
667         if (cap_smb_fname == NULL) {
668                 TALLOC_FREE(cappath);
669                 errno = ENOMEM;
670                 return -1;
671         }
672         ret = SMB_VFS_NEXT_MKNOD(handle, cap_smb_fname, mode, dev);
673         if (ret == -1) {
674                 saved_errno = errno;
675         }
676         TALLOC_FREE(cappath);
677         TALLOC_FREE(cap_smb_fname);
678         if (saved_errno != 0) {
679                 errno = saved_errno;
680         }
681         return ret;
682 }
683
684 static struct smb_filename *cap_realpath(vfs_handle_struct *handle,
685                         TALLOC_CTX *ctx,
686                         const struct smb_filename *smb_fname)
687 {
688         /* monyo need capencode'ed and capdecode'ed? */
689         struct smb_filename *cap_smb_fname = NULL;
690         struct smb_filename *return_fname = NULL;
691         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
692         int saved_errno = 0;
693
694         if (!cappath) {
695                 errno = ENOMEM;
696                 return NULL;
697         }
698         cap_smb_fname = synthetic_smb_fname(ctx,
699                                         cappath,
700                                         NULL,
701                                         NULL,
702                                         smb_fname->flags);
703         if (cap_smb_fname == NULL) {
704                 TALLOC_FREE(cappath);
705                 errno = ENOMEM;
706                 return NULL;
707         }
708         return_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, cap_smb_fname);
709         if (return_fname == NULL) {
710                 saved_errno = errno;
711         }
712         TALLOC_FREE(cappath);
713         TALLOC_FREE(cap_smb_fname);
714         if (saved_errno != 0) {
715                 errno = saved_errno;
716         }
717         return return_fname;
718 }
719
720 static SMB_ACL_T cap_sys_acl_get_file(vfs_handle_struct *handle,
721                                 const struct smb_filename *smb_fname,
722                                 SMB_ACL_TYPE_T type,
723                                 TALLOC_CTX *mem_ctx)
724 {
725         struct smb_filename *cap_smb_fname = NULL;
726         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
727         SMB_ACL_T ret;
728         int saved_errno = 0;
729
730         if (!cappath) {
731                 errno = ENOMEM;
732                 return (SMB_ACL_T)NULL;
733         }
734         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
735                                         cappath,
736                                         NULL,
737                                         NULL,
738                                         smb_fname->flags);
739         if (cap_smb_fname == NULL) {
740                 TALLOC_FREE(cappath);
741                 errno = ENOMEM;
742                 return (SMB_ACL_T)NULL;
743         }
744         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, cap_smb_fname,
745                                 type, mem_ctx);
746         if (ret == NULL) {
747                 saved_errno = errno;
748         }
749         TALLOC_FREE(cappath);
750         TALLOC_FREE(cap_smb_fname);
751         if (saved_errno != 0) {
752                 errno = saved_errno;
753         }
754         return ret;
755 }
756
757 static int cap_sys_acl_set_file(vfs_handle_struct *handle,
758                         const struct smb_filename *smb_fname,
759                         SMB_ACL_TYPE_T acltype,
760                         SMB_ACL_T theacl)
761 {
762         struct smb_filename *cap_smb_fname = NULL;
763         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
764         int ret;
765         int saved_errno = 0;
766
767         if (!cappath) {
768                 errno = ENOMEM;
769                 return -1;
770         }
771         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
772                                         cappath,
773                                         NULL,
774                                         NULL,
775                                         smb_fname->flags);
776         if (cap_smb_fname == NULL) {
777                 TALLOC_FREE(cappath);
778                 errno = ENOMEM;
779                 return -1;
780         }
781         ret =  SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, cap_smb_fname,
782                                 acltype, theacl);
783         if (ret == -1) {
784                 saved_errno = errno;
785         }
786         TALLOC_FREE(cappath);
787         TALLOC_FREE(cap_smb_fname);
788         if (saved_errno != 0) {
789                 errno = saved_errno;
790         }
791         return ret;
792 }
793
794 static int cap_sys_acl_delete_def_file(vfs_handle_struct *handle,
795                         const struct smb_filename *smb_fname)
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_DELETE_DEF_FILE(handle, cap_smb_fname);
817         if (ret == -1) {
818                 saved_errno = errno;
819         }
820         TALLOC_FREE(cappath);
821         TALLOC_FREE(cap_smb_fname);
822         if (saved_errno) {
823                 errno = saved_errno;
824         }
825         return ret;
826 }
827
828 static ssize_t cap_getxattr(vfs_handle_struct *handle,
829                         const struct smb_filename *smb_fname,
830                         const char *name,
831                         void *value,
832                         size_t size)
833 {
834         struct smb_filename *cap_smb_fname = NULL;
835         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
836         char *capname = capencode(talloc_tos(), name);
837         ssize_t ret;
838         int saved_errno = 0;
839
840         if (!cappath || !capname) {
841                 errno = ENOMEM;
842                 return -1;
843         }
844         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
845                                         cappath,
846                                         NULL,
847                                         NULL,
848                                         smb_fname->flags);
849         if (cap_smb_fname == NULL) {
850                 TALLOC_FREE(cappath);
851                 TALLOC_FREE(capname);
852                 errno = ENOMEM;
853                 return -1;
854         }
855         ret = SMB_VFS_NEXT_GETXATTR(handle, cap_smb_fname,
856                         capname, value, size);
857         if (ret == -1) {
858                 saved_errno = errno;
859         }
860         TALLOC_FREE(cappath);
861         TALLOC_FREE(capname);
862         TALLOC_FREE(cap_smb_fname);
863         if (saved_errno) {
864                 errno = saved_errno;
865         }
866         return ret;
867 }
868
869 static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
870 {
871         char *cappath = capencode(talloc_tos(), path);
872
873         if (!cappath) {
874                 errno = ENOMEM;
875                 return -1;
876         }
877         return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
878 }
879
880 static ssize_t cap_listxattr(vfs_handle_struct *handle,
881                                 const struct smb_filename *smb_fname,
882                                 char *list,
883                                 size_t size)
884 {
885         struct smb_filename *cap_smb_fname = NULL;
886         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
887         ssize_t ret;
888         int saved_errno = 0;
889
890         if (!cappath) {
891                 errno = ENOMEM;
892                 return -1;
893         }
894         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
895                                         cappath,
896                                         NULL,
897                                         NULL,
898                                         smb_fname->flags);
899         if (cap_smb_fname == NULL) {
900                 TALLOC_FREE(cappath);
901                 errno = ENOMEM;
902                 return -1;
903         }
904         ret = SMB_VFS_NEXT_LISTXATTR(handle, cap_smb_fname, list, size);
905         if (ret == -1) {
906                 saved_errno = errno;
907         }
908         TALLOC_FREE(cappath);
909         TALLOC_FREE(cap_smb_fname);
910         if (saved_errno) {
911                 errno = saved_errno;
912         }
913         return ret;
914 }
915
916 static int cap_removexattr(vfs_handle_struct *handle,
917                                 const struct smb_filename *smb_fname,
918                                 const char *name)
919 {
920         struct smb_filename *cap_smb_fname = NULL;
921         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
922         char *capname = capencode(talloc_tos(), name);
923         int ret;
924         int saved_errno = 0;
925
926         if (!cappath || !capname) {
927                 errno = ENOMEM;
928                 return -1;
929         }
930         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
931                                         cappath,
932                                         NULL,
933                                         NULL,
934                                         smb_fname->flags);
935         if (cap_smb_fname == NULL) {
936                 TALLOC_FREE(cappath);
937                 TALLOC_FREE(capname);
938                 errno = ENOMEM;
939                 return -1;
940         }
941         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, cap_smb_fname, capname);
942         if (ret == -1) {
943                 saved_errno = errno;
944         }
945         TALLOC_FREE(cappath);
946         TALLOC_FREE(capname);
947         TALLOC_FREE(cap_smb_fname);
948         if (saved_errno) {
949                 errno = saved_errno;
950         }
951         return ret;
952 }
953
954 static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
955 {
956         char *cappath = capencode(talloc_tos(), path);
957
958         if (!cappath) {
959                 errno = ENOMEM;
960                 return -1;
961         }
962         return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
963 }
964
965 static int cap_setxattr(vfs_handle_struct *handle,
966                         const struct smb_filename *smb_fname,
967                         const char *name,
968                         const void *value,
969                         size_t size,
970                         int flags)
971 {
972         struct smb_filename *cap_smb_fname = NULL;
973         char *cappath = capencode(talloc_tos(), smb_fname->base_name);
974         char *capname = capencode(talloc_tos(), name);
975         int ret;
976         int saved_errno = 0;
977
978         if (!cappath || !capname) {
979                 errno = ENOMEM;
980                 return -1;
981         }
982         cap_smb_fname = synthetic_smb_fname(talloc_tos(),
983                                         cappath,
984                                         NULL,
985                                         NULL,
986                                         smb_fname->flags);
987         if (cap_smb_fname == NULL) {
988                 TALLOC_FREE(cappath);
989                 TALLOC_FREE(capname);
990                 errno = ENOMEM;
991                 return -1;
992         }
993         ret = SMB_VFS_NEXT_SETXATTR(handle, cap_smb_fname,
994                                 capname, value, size, flags);
995         if (ret == -1) {
996                 saved_errno = errno;
997         }
998         TALLOC_FREE(cappath);
999         TALLOC_FREE(capname);
1000         TALLOC_FREE(cap_smb_fname);
1001         if (saved_errno) {
1002                 errno = saved_errno;
1003         }
1004         return ret;
1005 }
1006
1007 static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
1008 {
1009         char *cappath = capencode(talloc_tos(), path);
1010
1011         if (!cappath) {
1012                 errno = ENOMEM;
1013                 return -1;
1014         }
1015         return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
1016 }
1017
1018 static struct vfs_fn_pointers vfs_cap_fns = {
1019         .disk_free_fn = cap_disk_free,
1020         .get_quota_fn = cap_get_quota,
1021         .opendir_fn = cap_opendir,
1022         .readdir_fn = cap_readdir,
1023         .mkdir_fn = cap_mkdir,
1024         .rmdir_fn = cap_rmdir,
1025         .open_fn = cap_open,
1026         .renameat_fn = cap_renameat,
1027         .stat_fn = cap_stat,
1028         .lstat_fn = cap_lstat,
1029         .unlink_fn = cap_unlink,
1030         .chmod_fn = cap_chmod,
1031         .chown_fn = cap_chown,
1032         .lchown_fn = cap_lchown,
1033         .chdir_fn = cap_chdir,
1034         .ntimes_fn = cap_ntimes,
1035         .symlink_fn = cap_symlink,
1036         .readlink_fn = cap_readlink,
1037         .linkat_fn = cap_linkat,
1038         .mknod_fn = cap_mknod,
1039         .realpath_fn = cap_realpath,
1040         .sys_acl_get_file_fn = cap_sys_acl_get_file,
1041         .sys_acl_set_file_fn = cap_sys_acl_set_file,
1042         .sys_acl_delete_def_file_fn = cap_sys_acl_delete_def_file,
1043         .getxattr_fn = cap_getxattr,
1044         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1045         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1046         .fgetxattr_fn = cap_fgetxattr,
1047         .listxattr_fn = cap_listxattr,
1048         .removexattr_fn = cap_removexattr,
1049         .fremovexattr_fn = cap_fremovexattr,
1050         .setxattr_fn = cap_setxattr,
1051         .fsetxattr_fn = cap_fsetxattr
1052 };
1053
1054 static_decl_vfs;
1055 NTSTATUS vfs_cap_init(TALLOC_CTX *ctx)
1056 {
1057         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "cap",
1058                                 &vfs_cap_fns);
1059 }
1060
1061 /* For CAP functions */
1062 #define hex_tag ':'
1063 #define hex2bin(c)              hex2bin_table[(unsigned char)(c)]
1064 #define bin2hex(c)              bin2hex_table[(unsigned char)(c)]
1065 #define is_hex(s)               ((s)[0] == hex_tag)
1066
1067 static unsigned char hex2bin_table[256] = {
1068 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
1069 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
1070 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1071 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
1072 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x40 */
1073 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
1074 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1075 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x60 */
1076 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
1077 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
1078 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */
1079 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */
1080 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */
1081 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */
1082 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */
1083 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */
1084 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */
1085 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 */
1086 };
1087 static unsigned char bin2hex_table[256] = "0123456789abcdef";
1088
1089 /*******************************************************************
1090   original code -> ":xx"  - CAP format
1091 ********************************************************************/
1092
1093 static char *capencode(TALLOC_CTX *ctx, const char *from)
1094 {
1095         char *out = NULL;
1096         const char *p1;
1097         char *to = NULL;
1098         size_t len = 0;
1099
1100         for (p1 = from; *p1; p1++) {
1101                 if ((unsigned char)*p1 >= 0x80) {
1102                         len += 3;
1103                 } else {
1104                         len++;
1105                 }
1106         }
1107         len++;
1108
1109         to = talloc_array(ctx, char, len);
1110         if (!to) {
1111                 return NULL;
1112         }
1113
1114         for (out = to; *from;) {
1115                 /* buffer husoku error */
1116                 if ((unsigned char)*from >= 0x80) {
1117                         *out++ = hex_tag;
1118                         *out++ = bin2hex (((*from)>>4)&0x0f);
1119                         *out++ = bin2hex ((*from)&0x0f);
1120                         from++;
1121                 } else {
1122                         *out++ = *from++;
1123                 }
1124         }
1125         *out = '\0';
1126         return to;
1127 }
1128
1129 /*******************************************************************
1130   CAP -> original code
1131 ********************************************************************/
1132 /* ":xx" -> a byte */
1133
1134 static char *capdecode(TALLOC_CTX *ctx, const char *from)
1135 {
1136         const char *p1;
1137         char *out = NULL;
1138         char *to = NULL;
1139         size_t len = 0;
1140
1141         for (p1 = from; *p1; len++) {
1142                 if (is_hex(p1)) {
1143                         p1 += 3;
1144                 } else {
1145                         p1++;
1146                 }
1147         }
1148         len++;
1149
1150         to = talloc_array(ctx, char, len);
1151         if (!to) {
1152                 return NULL;
1153         }
1154
1155         for (out = to; *from;) {
1156                 if (is_hex(from)) {
1157                         *out++ = (hex2bin(from[1])<<4) | (hex2bin(from[2]));
1158                         from += 3;
1159                 } else {
1160                         *out++ = *from++;
1161                 }
1162         }
1163         *out = '\0';
1164         return to;
1165 }