Merge branch 'master' of ssh://jht@git.samba.org/data/git/samba
[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
27 /* cap functions */
28 static char *capencode(TALLOC_CTX *ctx, const char *from);
29 static char *capdecode(TALLOC_CTX *ctx, const char *from);
30
31 static uint64_t cap_disk_free(vfs_handle_struct *handle, const char *path,
32         bool small_query, uint64_t *bsize,
33         uint64_t *dfree, uint64_t *dsize)
34 {
35         char *cappath = capencode(talloc_tos(), path);
36
37         if (!cappath) {
38                 errno = ENOMEM;
39                 return (uint64_t)-1;
40         }
41         return SMB_VFS_NEXT_DISK_FREE(handle, cappath, small_query, bsize,
42                                         dfree, dsize);
43 }
44
45 static SMB_STRUCT_DIR *cap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
46 {
47         char *capname = capencode(talloc_tos(), fname);
48
49         if (!capname) {
50                 errno = ENOMEM;
51                 return NULL;
52         }
53         return SMB_VFS_NEXT_OPENDIR(handle, capname, mask, attr);
54 }
55
56 static SMB_STRUCT_DIRENT *cap_readdir(vfs_handle_struct *handle,
57                                       SMB_STRUCT_DIR *dirp,
58                                       SMB_STRUCT_STAT *sbuf)
59 {
60         SMB_STRUCT_DIRENT *result;
61         SMB_STRUCT_DIRENT *newdirent;
62         char *newname;
63         size_t newnamelen;
64         DEBUG(3,("cap: cap_readdir\n"));
65
66         result = SMB_VFS_NEXT_READDIR(handle, dirp, NULL);
67         if (!result) {
68                 return NULL;
69         }
70
71         newname = capdecode(talloc_tos(), result->d_name);
72         if (!newname) {
73                 return NULL;
74         }
75         DEBUG(3,("cap: cap_readdir: %s\n", newname));
76         newnamelen = strlen(newname)+1;
77         newdirent = (SMB_STRUCT_DIRENT *)TALLOC_ARRAY(talloc_tos(),
78                         char,
79                         sizeof(SMB_STRUCT_DIRENT)+
80                                 newnamelen);
81         if (!newdirent) {
82                 return NULL;
83         }
84         memcpy(newdirent, result, sizeof(SMB_STRUCT_DIRENT));
85         memcpy(&newdirent->d_name, newname, newnamelen);
86         return newdirent;
87 }
88
89 static int cap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
90 {
91         char *cappath = capencode(talloc_tos(), path);
92
93         if (!cappath) {
94                 errno = ENOMEM;
95                 return -1;
96         }
97         return SMB_VFS_NEXT_MKDIR(handle, cappath, mode);
98 }
99
100 static int cap_rmdir(vfs_handle_struct *handle, const char *path)
101 {
102         char *cappath = capencode(talloc_tos(), path);
103
104         if (!cappath) {
105                 errno = ENOMEM;
106                 return -1;
107         }
108         return SMB_VFS_NEXT_RMDIR(handle, cappath);
109 }
110
111 static int cap_open(vfs_handle_struct *handle, struct smb_filename *smb_fname,
112                     files_struct *fsp, int flags, mode_t mode)
113 {
114         char *cappath;
115         char *tmp_base_name = NULL;
116         int ret;
117
118         cappath = capencode(talloc_tos(), smb_fname->base_name);
119
120         if (!cappath) {
121                 errno = ENOMEM;
122                 return -1;
123         }
124
125         tmp_base_name = smb_fname->base_name;
126         smb_fname->base_name = cappath;
127
128         DEBUG(3,("cap: cap_open for %s\n", smb_fname_str_dbg(smb_fname)));
129         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
130
131         smb_fname->base_name = tmp_base_name;
132         TALLOC_FREE(cappath);
133
134         return ret;
135 }
136
137 static int cap_rename(vfs_handle_struct *handle,
138                       const struct smb_filename *smb_fname_src,
139                       const struct smb_filename *smb_fname_dst)
140 {
141         char *capold = NULL;
142         char *capnew = NULL;
143         struct smb_filename *smb_fname_src_tmp = NULL;
144         struct smb_filename *smb_fname_dst_tmp = NULL;
145         NTSTATUS status;
146         int ret = -1;
147
148         capold = capencode(talloc_tos(), smb_fname_src->base_name);
149         capnew = capencode(talloc_tos(), smb_fname_dst->base_name);
150         if (!capold || !capnew) {
151                 errno = ENOMEM;
152                 goto out;
153         }
154
155         /* Setup temporary smb_filename structs. */
156         status = copy_smb_filename(talloc_tos(), smb_fname_src,
157                                    &smb_fname_src_tmp);
158         if (!NT_STATUS_IS_OK(status)) {
159                 errno = map_errno_from_nt_status(status);
160                 goto out;
161         }
162         status = copy_smb_filename(talloc_tos(), smb_fname_dst,
163                                    &smb_fname_dst_tmp);
164         if (!NT_STATUS_IS_OK(status)) {
165                 errno = map_errno_from_nt_status(status);
166                 goto out;
167         }
168
169         smb_fname_src_tmp->base_name = capold;
170         smb_fname_dst_tmp->base_name = capnew;
171
172         ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_tmp,
173                                   smb_fname_dst_tmp);
174  out:
175         TALLOC_FREE(capold);
176         TALLOC_FREE(capnew);
177         TALLOC_FREE(smb_fname_src_tmp);
178         TALLOC_FREE(smb_fname_dst_tmp);
179
180         return ret;
181 }
182
183 static int cap_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
184 {
185         char *cappath;
186         char *tmp_base_name = NULL;
187         int ret;
188
189         cappath = capencode(talloc_tos(), smb_fname->base_name);
190
191         if (!cappath) {
192                 errno = ENOMEM;
193                 return -1;
194         }
195
196         tmp_base_name = smb_fname->base_name;
197         smb_fname->base_name = cappath;
198
199         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
200
201         smb_fname->base_name = tmp_base_name;
202         TALLOC_FREE(cappath);
203
204         return ret;
205 }
206
207 static int cap_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
208 {
209         char *cappath;
210         char *tmp_base_name = NULL;
211         int ret;
212
213         cappath = capencode(talloc_tos(), smb_fname->base_name);
214
215         if (!cappath) {
216                 errno = ENOMEM;
217                 return -1;
218         }
219
220         tmp_base_name = smb_fname->base_name;
221         smb_fname->base_name = cappath;
222
223         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
224
225         smb_fname->base_name = tmp_base_name;
226         TALLOC_FREE(cappath);
227
228         return ret;
229 }
230
231 static int cap_unlink(vfs_handle_struct *handle,
232                       const struct smb_filename *smb_fname)
233 {
234         struct smb_filename *smb_fname_tmp = NULL;
235         char *cappath = NULL;
236         NTSTATUS status;
237         int ret;
238
239         cappath = capencode(talloc_tos(), smb_fname->base_name);
240         if (!cappath) {
241                 errno = ENOMEM;
242                 return -1;
243         }
244
245         /* Setup temporary smb_filename structs. */
246         status = copy_smb_filename(talloc_tos(), smb_fname,
247                                    &smb_fname_tmp);
248         if (!NT_STATUS_IS_OK(status)) {
249                 errno = map_errno_from_nt_status(status);
250                 return -1;
251         }
252
253         smb_fname_tmp->base_name = cappath;
254
255         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
256
257         TALLOC_FREE(smb_fname_tmp);
258         return ret;
259 }
260
261 static int cap_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
262 {
263         char *cappath = capencode(talloc_tos(), path);
264
265         if (!cappath) {
266                 errno = ENOMEM;
267                 return -1;
268         }
269         return SMB_VFS_NEXT_CHMOD(handle, cappath, mode);
270 }
271
272 static int cap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
273 {
274         char *cappath = capencode(talloc_tos(), path);
275
276         if (!cappath) {
277                 errno = ENOMEM;
278                 return -1;
279         }
280         return SMB_VFS_NEXT_CHOWN(handle, cappath, uid, gid);
281 }
282
283 static int cap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
284 {
285         char *cappath = capencode(talloc_tos(), path);
286
287         if (!cappath) {
288                 errno = ENOMEM;
289                 return -1;
290         }
291         return SMB_VFS_NEXT_LCHOWN(handle, cappath, uid, gid);
292 }
293
294 static int cap_chdir(vfs_handle_struct *handle, const char *path)
295 {
296         char *cappath = capencode(talloc_tos(), path);
297
298         if (!cappath) {
299                 errno = ENOMEM;
300                 return -1;
301         }
302         DEBUG(3,("cap: cap_chdir for %s\n", path));
303         return SMB_VFS_NEXT_CHDIR(handle, cappath);
304 }
305
306 static int cap_ntimes(vfs_handle_struct *handle,
307                       const struct smb_filename *smb_fname,
308                       struct smb_file_time *ft)
309 {
310         struct smb_filename *smb_fname_tmp = NULL;
311         char *cappath = NULL;
312         NTSTATUS status;
313         int ret;
314
315         cappath = capencode(talloc_tos(), smb_fname->base_name);
316
317         if (!cappath) {
318                 errno = ENOMEM;
319                 return -1;
320         }
321
322         /* Setup temporary smb_filename structs. */
323         status = copy_smb_filename(talloc_tos(), smb_fname,
324                                    &smb_fname_tmp);
325         if (!NT_STATUS_IS_OK(status)) {
326                 errno = map_errno_from_nt_status(status);
327                 return -1;
328         }
329
330         smb_fname_tmp->base_name = cappath;
331
332         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
333
334         TALLOC_FREE(smb_fname_tmp);
335         return ret;
336 }
337
338
339 static int cap_symlink(vfs_handle_struct *handle, const char *oldpath,
340                        const char *newpath)
341 {
342         char *capold = capencode(talloc_tos(), oldpath);
343         char *capnew = capencode(talloc_tos(), newpath);
344
345         if (!capold || !capnew) {
346                 errno = ENOMEM;
347                 return -1;
348         }
349         return SMB_VFS_NEXT_SYMLINK(handle, capold, capnew);
350 }
351
352 static int cap_readlink(vfs_handle_struct *handle, const char *path,
353                         char *buf, size_t bufsiz)
354 {
355         char *cappath = capencode(talloc_tos(), path);
356
357         if (!cappath) {
358                 errno = ENOMEM;
359                 return -1;
360         }
361         return SMB_VFS_NEXT_READLINK(handle, cappath, buf, bufsiz);
362 }
363
364 static int cap_link(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
365 {
366         char *capold = capencode(talloc_tos(), oldpath);
367         char *capnew = capencode(talloc_tos(), newpath);
368
369         if (!capold || !capnew) {
370                 errno = ENOMEM;
371                 return -1;
372         }
373         return SMB_VFS_NEXT_LINK(handle, capold, capnew);
374 }
375
376 static int cap_mknod(vfs_handle_struct *handle, const char *path, mode_t mode, SMB_DEV_T dev)
377 {
378         char *cappath = capencode(talloc_tos(), path);
379
380         if (!cappath) {
381                 errno = ENOMEM;
382                 return -1;
383         }
384         return SMB_VFS_NEXT_MKNOD(handle, cappath, mode, dev);
385 }
386
387 static char *cap_realpath(vfs_handle_struct *handle, const char *path, char *resolved_path)
388 {
389         /* monyo need capencode'ed and capdecode'ed? */
390         char *cappath = capencode(talloc_tos(), path);
391
392         if (!cappath) {
393                 errno = ENOMEM;
394                 return NULL;
395         }
396         return SMB_VFS_NEXT_REALPATH(handle, path, resolved_path);
397 }
398
399 static int cap_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t mode)
400 {
401         char *cappath = capencode(talloc_tos(), path);
402
403         /* If the underlying VFS doesn't have ACL support... */
404         if (!handle->vfs_next.ops.chmod_acl) {
405                 errno = ENOSYS;
406                 return -1;
407         }
408         if (!cappath) {
409                 errno = ENOMEM;
410                 return -1;
411         }
412         return SMB_VFS_NEXT_CHMOD_ACL(handle, cappath, mode);
413 }
414
415 static SMB_ACL_T cap_sys_acl_get_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type)
416 {
417         char *cappath = capencode(talloc_tos(), path);
418
419         if (!cappath) {
420                 errno = ENOMEM;
421                 return (SMB_ACL_T)NULL;
422         }
423         return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, cappath, type);
424 }
425
426 static int cap_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
427 {
428         char *cappath = capencode(talloc_tos(), path);
429
430         if (!cappath) {
431                 errno = ENOMEM;
432                 return -1;
433         }
434         return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, cappath, acltype, theacl);
435 }
436
437 static int cap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
438 {
439         char *cappath = capencode(talloc_tos(), path);
440
441         if (!cappath) {
442                 errno = ENOMEM;
443                 return -1;
444         }
445         return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, cappath);
446 }
447
448 static ssize_t cap_getxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t size)
449 {
450         char *cappath = capencode(talloc_tos(), path);
451         char *capname = capencode(talloc_tos(), name);
452
453         if (!cappath || !capname) {
454                 errno = ENOMEM;
455                 return -1;
456         }
457         return SMB_VFS_NEXT_GETXATTR(handle, cappath, capname, value, size);
458 }
459
460 static ssize_t cap_lgetxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t
461 size)
462 {
463         char *cappath = capencode(talloc_tos(), path);
464         char *capname = capencode(talloc_tos(), name);
465
466         if (!cappath || !capname) {
467                 errno = ENOMEM;
468                 return -1;
469         }
470         return SMB_VFS_NEXT_LGETXATTR(handle, cappath, capname, value, size);
471 }
472
473 static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
474 {
475         char *cappath = capencode(talloc_tos(), path);
476
477         if (!cappath) {
478                 errno = ENOMEM;
479                 return -1;
480         }
481         return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
482 }
483
484 static ssize_t cap_listxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
485 {
486         char *cappath = capencode(talloc_tos(), path);
487
488         if (!cappath) {
489                 errno = ENOMEM;
490                 return -1;
491         }
492         return SMB_VFS_NEXT_LISTXATTR(handle, cappath, list, size);
493 }
494
495 static ssize_t cap_llistxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
496 {
497         char *cappath = capencode(talloc_tos(), path);
498
499         if (!cappath) {
500                 errno = ENOMEM;
501                 return -1;
502         }
503         return SMB_VFS_NEXT_LLISTXATTR(handle, cappath, list, size);
504 }
505
506 static int cap_removexattr(vfs_handle_struct *handle, const char *path, const char *name)
507 {
508         char *cappath = capencode(talloc_tos(), path);
509         char *capname = capencode(talloc_tos(), name);
510
511         if (!cappath || !capname) {
512                 errno = ENOMEM;
513                 return -1;
514         }
515         return SMB_VFS_NEXT_REMOVEXATTR(handle, cappath, capname);
516 }
517
518 static int cap_lremovexattr(vfs_handle_struct *handle, const char *path, const char *name)
519 {
520         char *cappath = capencode(talloc_tos(), path);
521         char *capname = capencode(talloc_tos(), name);
522
523         if (!cappath || !capname) {
524                 errno = ENOMEM;
525                 return -1;
526         }
527         return SMB_VFS_NEXT_LREMOVEXATTR(handle, cappath, capname);
528 }
529
530 static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
531 {
532         char *cappath = capencode(talloc_tos(), path);
533
534         if (!cappath) {
535                 errno = ENOMEM;
536                 return -1;
537         }
538         return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
539 }
540
541 static int cap_setxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
542 {
543         char *cappath = capencode(talloc_tos(), path);
544         char *capname = capencode(talloc_tos(), name);
545
546         if (!cappath || !capname) {
547                 errno = ENOMEM;
548                 return -1;
549         }
550         return SMB_VFS_NEXT_SETXATTR(handle, cappath, capname, value, size, flags);
551 }
552
553 static int cap_lsetxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
554 {
555         char *cappath = capencode(talloc_tos(), path);
556         char *capname = capencode(talloc_tos(), name);
557
558         if (!cappath || !capname) {
559                 errno = ENOMEM;
560                 return -1;
561         }
562         return SMB_VFS_NEXT_LSETXATTR(handle, cappath, capname, value, size, flags);
563 }
564
565 static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
566 {
567         char *cappath = capencode(talloc_tos(), path);
568
569         if (!cappath) {
570                 errno = ENOMEM;
571                 return -1;
572         }
573         return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
574 }
575
576 /* VFS operations structure */
577
578 static vfs_op_tuple cap_op_tuples[] = {
579
580         /* Disk operations */
581
582         {SMB_VFS_OP(cap_disk_free),                     SMB_VFS_OP_DISK_FREE,           SMB_VFS_LAYER_TRANSPARENT},
583
584         /* Directory operations */
585
586         {SMB_VFS_OP(cap_opendir),                       SMB_VFS_OP_OPENDIR,             SMB_VFS_LAYER_TRANSPARENT},
587         {SMB_VFS_OP(cap_readdir),                       SMB_VFS_OP_READDIR,             SMB_VFS_LAYER_TRANSPARENT},
588         {SMB_VFS_OP(cap_mkdir),                 SMB_VFS_OP_MKDIR,               SMB_VFS_LAYER_TRANSPARENT},
589         {SMB_VFS_OP(cap_rmdir),                 SMB_VFS_OP_RMDIR,               SMB_VFS_LAYER_TRANSPARENT},
590
591         /* File operations */
592
593         {SMB_VFS_OP(cap_open),                          SMB_VFS_OP_OPEN,                SMB_VFS_LAYER_TRANSPARENT},
594         {SMB_VFS_OP(cap_rename),                        SMB_VFS_OP_RENAME,              SMB_VFS_LAYER_TRANSPARENT},
595         {SMB_VFS_OP(cap_stat),                          SMB_VFS_OP_STAT,                SMB_VFS_LAYER_TRANSPARENT},
596         {SMB_VFS_OP(cap_lstat),                 SMB_VFS_OP_LSTAT,               SMB_VFS_LAYER_TRANSPARENT},
597         {SMB_VFS_OP(cap_unlink),                        SMB_VFS_OP_UNLINK,              SMB_VFS_LAYER_TRANSPARENT},
598         {SMB_VFS_OP(cap_chmod),                 SMB_VFS_OP_CHMOD,               SMB_VFS_LAYER_TRANSPARENT},
599         {SMB_VFS_OP(cap_chown),                 SMB_VFS_OP_CHOWN,               SMB_VFS_LAYER_TRANSPARENT},
600         {SMB_VFS_OP(cap_lchown),                SMB_VFS_OP_LCHOWN,              SMB_VFS_LAYER_TRANSPARENT},
601         {SMB_VFS_OP(cap_chdir),                 SMB_VFS_OP_CHDIR,               SMB_VFS_LAYER_TRANSPARENT},
602         {SMB_VFS_OP(cap_ntimes),                        SMB_VFS_OP_NTIMES,              SMB_VFS_LAYER_TRANSPARENT},
603         {SMB_VFS_OP(cap_symlink),                       SMB_VFS_OP_SYMLINK,             SMB_VFS_LAYER_TRANSPARENT},
604         {SMB_VFS_OP(cap_readlink),                      SMB_VFS_OP_READLINK,            SMB_VFS_LAYER_TRANSPARENT},
605         {SMB_VFS_OP(cap_link),                          SMB_VFS_OP_LINK,                SMB_VFS_LAYER_TRANSPARENT},
606         {SMB_VFS_OP(cap_mknod),                 SMB_VFS_OP_MKNOD,               SMB_VFS_LAYER_TRANSPARENT},
607         {SMB_VFS_OP(cap_realpath),                      SMB_VFS_OP_REALPATH,            SMB_VFS_LAYER_TRANSPARENT},
608
609         /* POSIX ACL operations */
610
611         {SMB_VFS_OP(cap_chmod_acl),                     SMB_VFS_OP_CHMOD_ACL,           SMB_VFS_LAYER_TRANSPARENT},
612
613         {SMB_VFS_OP(cap_sys_acl_get_file),              SMB_VFS_OP_SYS_ACL_GET_FILE,            SMB_VFS_LAYER_TRANSPARENT},
614         {SMB_VFS_OP(cap_sys_acl_set_file),              SMB_VFS_OP_SYS_ACL_SET_FILE,            SMB_VFS_LAYER_TRANSPARENT},
615         {SMB_VFS_OP(cap_sys_acl_delete_def_file),       SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,     SMB_VFS_LAYER_TRANSPARENT},
616
617         /* EA operations. */
618         {SMB_VFS_OP(cap_getxattr),                      SMB_VFS_OP_GETXATTR,                    SMB_VFS_LAYER_TRANSPARENT},
619         {SMB_VFS_OP(cap_lgetxattr),                     SMB_VFS_OP_LGETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
620         {SMB_VFS_OP(cap_fgetxattr),                     SMB_VFS_OP_FGETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
621         {SMB_VFS_OP(cap_listxattr),                     SMB_VFS_OP_LISTXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
622         {SMB_VFS_OP(cap_llistxattr),                    SMB_VFS_OP_LLISTXATTR,                  SMB_VFS_LAYER_TRANSPARENT},
623         {SMB_VFS_OP(cap_removexattr),                   SMB_VFS_OP_REMOVEXATTR,                 SMB_VFS_LAYER_TRANSPARENT},
624         {SMB_VFS_OP(cap_lremovexattr),                  SMB_VFS_OP_LREMOVEXATTR,                SMB_VFS_LAYER_TRANSPARENT},
625         {SMB_VFS_OP(cap_fremovexattr),                  SMB_VFS_OP_FREMOVEXATTR,                SMB_VFS_LAYER_TRANSPARENT},
626         {SMB_VFS_OP(cap_setxattr),                      SMB_VFS_OP_SETXATTR,                    SMB_VFS_LAYER_TRANSPARENT},
627         {SMB_VFS_OP(cap_lsetxattr),                     SMB_VFS_OP_LSETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
628         {SMB_VFS_OP(cap_fsetxattr),                     SMB_VFS_OP_FSETXATTR,                   SMB_VFS_LAYER_TRANSPARENT},
629
630         {NULL,                                          SMB_VFS_OP_NOOP,                        SMB_VFS_LAYER_NOOP}
631 };
632
633 NTSTATUS vfs_cap_init(void);
634 NTSTATUS vfs_cap_init(void)
635 {
636         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "cap", cap_op_tuples);
637 }
638
639 /* For CAP functions */
640 #define hex_tag ':'
641 #define hex2bin(c)              hex2bin_table[(unsigned char)(c)]
642 #define bin2hex(c)              bin2hex_table[(unsigned char)(c)]
643 #define is_hex(s)               ((s)[0] == hex_tag)
644
645 static unsigned char hex2bin_table[256] = {
646 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
647 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
648 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
649 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
650 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x40 */
651 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
653 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x60 */
654 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
655 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */
657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */
658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */
659 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */
660 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */
661 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */
662 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */
663 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 */
664 };
665 static unsigned char bin2hex_table[256] = "0123456789abcdef";
666
667 /*******************************************************************
668   original code -> ":xx"  - CAP format
669 ********************************************************************/
670
671 static char *capencode(TALLOC_CTX *ctx, const char *from)
672 {
673         char *out = NULL;
674         const char *p1;
675         char *to = NULL;
676         size_t len = 0;
677
678         for (p1 = from; *p1; p1++) {
679                 if ((unsigned char)*p1 >= 0x80) {
680                         len += 3;
681                 } else {
682                         len++;
683                 }
684         }
685         len++;
686
687         to = TALLOC_ARRAY(ctx, char, len);
688         if (!to) {
689                 return NULL;
690         }
691
692         for (out = to; *from;) {
693                 /* buffer husoku error */
694                 if ((unsigned char)*from >= 0x80) {
695                         *out++ = hex_tag;
696                         *out++ = bin2hex (((*from)>>4)&0x0f);
697                         *out++ = bin2hex ((*from)&0x0f);
698                         from++;
699                 } else {
700                         *out++ = *from++;
701                 }
702         }
703         *out = '\0';
704         return to;
705 }
706
707 /*******************************************************************
708   CAP -> original code
709 ********************************************************************/
710 /* ":xx" -> a byte */
711
712 static char *capdecode(TALLOC_CTX *ctx, const char *from)
713 {
714         const char *p1;
715         char *out = NULL;
716         char *to = NULL;
717         size_t len = 0;
718
719         for (p1 = from; *p1; len++) {
720                 if (is_hex(from)) {
721                         p1 += 3;
722                 } else {
723                         p1++;
724                 }
725         }
726
727         to = TALLOC_ARRAY(ctx, char, len);
728         if (!to) {
729                 return NULL;
730         }
731
732         for (out = to; *from;) {
733                 if (is_hex(from)) {
734                         *out++ = (hex2bin(from[1])<<4) | (hex2bin(from[2]));
735                         from += 3;
736                 } else {
737                         *out++ = *from++;
738                 }
739         }
740         *out = '\0';
741         return to;
742 }