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