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