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