VFS: Modify opendir to take a const struct smb_filename * instead of const char *
[bbaumbach/samba-autobuild/.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, const char *path, mode_t mode)
308 {
309         char *cappath = capencode(talloc_tos(), path);
310
311         if (!cappath) {
312                 errno = ENOMEM;
313                 return -1;
314         }
315         return SMB_VFS_NEXT_CHMOD(handle, cappath, mode);
316 }
317
318 static int cap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
319 {
320         char *cappath = capencode(talloc_tos(), path);
321
322         if (!cappath) {
323                 errno = ENOMEM;
324                 return -1;
325         }
326         return SMB_VFS_NEXT_CHOWN(handle, cappath, uid, gid);
327 }
328
329 static int cap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
330 {
331         char *cappath = capencode(talloc_tos(), path);
332
333         if (!cappath) {
334                 errno = ENOMEM;
335                 return -1;
336         }
337         return SMB_VFS_NEXT_LCHOWN(handle, cappath, uid, gid);
338 }
339
340 static int cap_chdir(vfs_handle_struct *handle, const char *path)
341 {
342         char *cappath = capencode(talloc_tos(), path);
343
344         if (!cappath) {
345                 errno = ENOMEM;
346                 return -1;
347         }
348         DEBUG(3,("cap: cap_chdir for %s\n", path));
349         return SMB_VFS_NEXT_CHDIR(handle, cappath);
350 }
351
352 static int cap_ntimes(vfs_handle_struct *handle,
353                       const struct smb_filename *smb_fname,
354                       struct smb_file_time *ft)
355 {
356         struct smb_filename *smb_fname_tmp = NULL;
357         char *cappath = NULL;
358         int ret;
359
360         cappath = capencode(talloc_tos(), smb_fname->base_name);
361
362         if (!cappath) {
363                 errno = ENOMEM;
364                 return -1;
365         }
366
367         /* Setup temporary smb_filename structs. */
368         smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
369         if (smb_fname_tmp == NULL) {
370                 errno = ENOMEM;
371                 return -1;
372         }
373
374         smb_fname_tmp->base_name = cappath;
375
376         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
377
378         TALLOC_FREE(smb_fname_tmp);
379         return ret;
380 }
381
382
383 static int cap_symlink(vfs_handle_struct *handle, const char *oldpath,
384                        const char *newpath)
385 {
386         char *capold = capencode(talloc_tos(), oldpath);
387         char *capnew = capencode(talloc_tos(), newpath);
388
389         if (!capold || !capnew) {
390                 errno = ENOMEM;
391                 return -1;
392         }
393         return SMB_VFS_NEXT_SYMLINK(handle, capold, capnew);
394 }
395
396 static int cap_readlink(vfs_handle_struct *handle, const char *path,
397                         char *buf, size_t bufsiz)
398 {
399         char *cappath = capencode(talloc_tos(), path);
400
401         if (!cappath) {
402                 errno = ENOMEM;
403                 return -1;
404         }
405         return SMB_VFS_NEXT_READLINK(handle, cappath, buf, bufsiz);
406 }
407
408 static int cap_link(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
409 {
410         char *capold = capencode(talloc_tos(), oldpath);
411         char *capnew = capencode(talloc_tos(), newpath);
412
413         if (!capold || !capnew) {
414                 errno = ENOMEM;
415                 return -1;
416         }
417         return SMB_VFS_NEXT_LINK(handle, capold, capnew);
418 }
419
420 static int cap_mknod(vfs_handle_struct *handle, const char *path, mode_t mode, SMB_DEV_T dev)
421 {
422         char *cappath = capencode(talloc_tos(), path);
423
424         if (!cappath) {
425                 errno = ENOMEM;
426                 return -1;
427         }
428         return SMB_VFS_NEXT_MKNOD(handle, cappath, mode, dev);
429 }
430
431 static char *cap_realpath(vfs_handle_struct *handle, const char *path)
432 {
433         /* monyo need capencode'ed and capdecode'ed? */
434         char *cappath = capencode(talloc_tos(), path);
435
436         if (!cappath) {
437                 errno = ENOMEM;
438                 return NULL;
439         }
440         return SMB_VFS_NEXT_REALPATH(handle, cappath);
441 }
442
443 static int cap_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t mode)
444 {
445         char *cappath = capencode(talloc_tos(), path);
446
447         /* If the underlying VFS doesn't have ACL support... */
448         if (!cappath) {
449                 errno = ENOMEM;
450                 return -1;
451         }
452         return SMB_VFS_NEXT_CHMOD_ACL(handle, cappath, mode);
453 }
454
455 static SMB_ACL_T cap_sys_acl_get_file(vfs_handle_struct *handle,
456                                       const char *path, SMB_ACL_TYPE_T type,
457                                       TALLOC_CTX *mem_ctx)
458 {
459         char *cappath = capencode(talloc_tos(), path);
460
461         if (!cappath) {
462                 errno = ENOMEM;
463                 return (SMB_ACL_T)NULL;
464         }
465         return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, cappath, type, mem_ctx);
466 }
467
468 static int cap_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
469 {
470         char *cappath = capencode(talloc_tos(), path);
471
472         if (!cappath) {
473                 errno = ENOMEM;
474                 return -1;
475         }
476         return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, cappath, acltype, theacl);
477 }
478
479 static int cap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
480 {
481         char *cappath = capencode(talloc_tos(), path);
482
483         if (!cappath) {
484                 errno = ENOMEM;
485                 return -1;
486         }
487         return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, cappath);
488 }
489
490 static ssize_t cap_getxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t size)
491 {
492         char *cappath = capencode(talloc_tos(), path);
493         char *capname = capencode(talloc_tos(), name);
494
495         if (!cappath || !capname) {
496                 errno = ENOMEM;
497                 return -1;
498         }
499         return SMB_VFS_NEXT_GETXATTR(handle, cappath, capname, value, size);
500 }
501
502 static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
503 {
504         char *cappath = capencode(talloc_tos(), path);
505
506         if (!cappath) {
507                 errno = ENOMEM;
508                 return -1;
509         }
510         return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
511 }
512
513 static ssize_t cap_listxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
514 {
515         char *cappath = capencode(talloc_tos(), path);
516
517         if (!cappath) {
518                 errno = ENOMEM;
519                 return -1;
520         }
521         return SMB_VFS_NEXT_LISTXATTR(handle, cappath, list, size);
522 }
523
524 static int cap_removexattr(vfs_handle_struct *handle, const char *path, const char *name)
525 {
526         char *cappath = capencode(talloc_tos(), path);
527         char *capname = capencode(talloc_tos(), name);
528
529         if (!cappath || !capname) {
530                 errno = ENOMEM;
531                 return -1;
532         }
533         return SMB_VFS_NEXT_REMOVEXATTR(handle, cappath, capname);
534 }
535
536 static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
537 {
538         char *cappath = capencode(talloc_tos(), path);
539
540         if (!cappath) {
541                 errno = ENOMEM;
542                 return -1;
543         }
544         return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
545 }
546
547 static int cap_setxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
548 {
549         char *cappath = capencode(talloc_tos(), path);
550         char *capname = capencode(talloc_tos(), name);
551
552         if (!cappath || !capname) {
553                 errno = ENOMEM;
554                 return -1;
555         }
556         return SMB_VFS_NEXT_SETXATTR(handle, cappath, capname, value, size, flags);
557 }
558
559 static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
560 {
561         char *cappath = capencode(talloc_tos(), path);
562
563         if (!cappath) {
564                 errno = ENOMEM;
565                 return -1;
566         }
567         return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
568 }
569
570 static struct vfs_fn_pointers vfs_cap_fns = {
571         .disk_free_fn = cap_disk_free,
572         .get_quota_fn = cap_get_quota,
573         .opendir_fn = cap_opendir,
574         .readdir_fn = cap_readdir,
575         .mkdir_fn = cap_mkdir,
576         .rmdir_fn = cap_rmdir,
577         .open_fn = cap_open,
578         .rename_fn = cap_rename,
579         .stat_fn = cap_stat,
580         .lstat_fn = cap_lstat,
581         .unlink_fn = cap_unlink,
582         .chmod_fn = cap_chmod,
583         .chown_fn = cap_chown,
584         .lchown_fn = cap_lchown,
585         .chdir_fn = cap_chdir,
586         .ntimes_fn = cap_ntimes,
587         .symlink_fn = cap_symlink,
588         .readlink_fn = cap_readlink,
589         .link_fn = cap_link,
590         .mknod_fn = cap_mknod,
591         .realpath_fn = cap_realpath,
592         .chmod_acl_fn = cap_chmod_acl,
593         .sys_acl_get_file_fn = cap_sys_acl_get_file,
594         .sys_acl_set_file_fn = cap_sys_acl_set_file,
595         .sys_acl_delete_def_file_fn = cap_sys_acl_delete_def_file,
596         .getxattr_fn = cap_getxattr,
597         .fgetxattr_fn = cap_fgetxattr,
598         .listxattr_fn = cap_listxattr,
599         .removexattr_fn = cap_removexattr,
600         .fremovexattr_fn = cap_fremovexattr,
601         .setxattr_fn = cap_setxattr,
602         .fsetxattr_fn = cap_fsetxattr
603 };
604
605 NTSTATUS vfs_cap_init(void);
606 NTSTATUS vfs_cap_init(void)
607 {
608         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "cap",
609                                 &vfs_cap_fns);
610 }
611
612 /* For CAP functions */
613 #define hex_tag ':'
614 #define hex2bin(c)              hex2bin_table[(unsigned char)(c)]
615 #define bin2hex(c)              bin2hex_table[(unsigned char)(c)]
616 #define is_hex(s)               ((s)[0] == hex_tag)
617
618 static unsigned char hex2bin_table[256] = {
619 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
620 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
621 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
622 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
623 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x40 */
624 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
625 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
626 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x60 */
627 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
628 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
629 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */
630 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */
631 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */
632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */
633 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */
634 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */
635 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */
636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 */
637 };
638 static unsigned char bin2hex_table[256] = "0123456789abcdef";
639
640 /*******************************************************************
641   original code -> ":xx"  - CAP format
642 ********************************************************************/
643
644 static char *capencode(TALLOC_CTX *ctx, const char *from)
645 {
646         char *out = NULL;
647         const char *p1;
648         char *to = NULL;
649         size_t len = 0;
650
651         for (p1 = from; *p1; p1++) {
652                 if ((unsigned char)*p1 >= 0x80) {
653                         len += 3;
654                 } else {
655                         len++;
656                 }
657         }
658         len++;
659
660         to = talloc_array(ctx, char, len);
661         if (!to) {
662                 return NULL;
663         }
664
665         for (out = to; *from;) {
666                 /* buffer husoku error */
667                 if ((unsigned char)*from >= 0x80) {
668                         *out++ = hex_tag;
669                         *out++ = bin2hex (((*from)>>4)&0x0f);
670                         *out++ = bin2hex ((*from)&0x0f);
671                         from++;
672                 } else {
673                         *out++ = *from++;
674                 }
675         }
676         *out = '\0';
677         return to;
678 }
679
680 /*******************************************************************
681   CAP -> original code
682 ********************************************************************/
683 /* ":xx" -> a byte */
684
685 static char *capdecode(TALLOC_CTX *ctx, const char *from)
686 {
687         const char *p1;
688         char *out = NULL;
689         char *to = NULL;
690         size_t len = 0;
691
692         for (p1 = from; *p1; len++) {
693                 if (is_hex(p1)) {
694                         p1 += 3;
695                 } else {
696                         p1++;
697                 }
698         }
699         len++;
700
701         to = talloc_array(ctx, char, len);
702         if (!to) {
703                 return NULL;
704         }
705
706         for (out = to; *from;) {
707                 if (is_hex(from)) {
708                         *out++ = (hex2bin(from[1])<<4) | (hex2bin(from[2]));
709                         from += 3;
710                 } else {
711                         *out++ = *from++;
712                 }
713         }
714         *out = '\0';
715         return to;
716 }