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