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