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