smbd: Remove unused [push_pull]_file_id_24
[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)
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, cappath);
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 (!cappath) {
405                 errno = ENOMEM;
406                 return -1;
407         }
408         return SMB_VFS_NEXT_CHMOD_ACL(handle, cappath, mode);
409 }
410
411 static SMB_ACL_T cap_sys_acl_get_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type)
412 {
413         char *cappath = capencode(talloc_tos(), path);
414
415         if (!cappath) {
416                 errno = ENOMEM;
417                 return (SMB_ACL_T)NULL;
418         }
419         return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, cappath, type);
420 }
421
422 static int cap_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
423 {
424         char *cappath = capencode(talloc_tos(), path);
425
426         if (!cappath) {
427                 errno = ENOMEM;
428                 return -1;
429         }
430         return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, cappath, acltype, theacl);
431 }
432
433 static int cap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
434 {
435         char *cappath = capencode(talloc_tos(), path);
436
437         if (!cappath) {
438                 errno = ENOMEM;
439                 return -1;
440         }
441         return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, cappath);
442 }
443
444 static ssize_t cap_getxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t size)
445 {
446         char *cappath = capencode(talloc_tos(), path);
447         char *capname = capencode(talloc_tos(), name);
448
449         if (!cappath || !capname) {
450                 errno = ENOMEM;
451                 return -1;
452         }
453         return SMB_VFS_NEXT_GETXATTR(handle, cappath, capname, value, size);
454 }
455
456 static ssize_t cap_lgetxattr(vfs_handle_struct *handle, const char *path, const char *name, void *value, size_t
457 size)
458 {
459         char *cappath = capencode(talloc_tos(), path);
460         char *capname = capencode(talloc_tos(), name);
461
462         if (!cappath || !capname) {
463                 errno = ENOMEM;
464                 return -1;
465         }
466         return SMB_VFS_NEXT_LGETXATTR(handle, cappath, capname, value, size);
467 }
468
469 static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
470 {
471         char *cappath = capencode(talloc_tos(), path);
472
473         if (!cappath) {
474                 errno = ENOMEM;
475                 return -1;
476         }
477         return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
478 }
479
480 static ssize_t cap_listxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
481 {
482         char *cappath = capencode(talloc_tos(), path);
483
484         if (!cappath) {
485                 errno = ENOMEM;
486                 return -1;
487         }
488         return SMB_VFS_NEXT_LISTXATTR(handle, cappath, list, size);
489 }
490
491 static ssize_t cap_llistxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
492 {
493         char *cappath = capencode(talloc_tos(), path);
494
495         if (!cappath) {
496                 errno = ENOMEM;
497                 return -1;
498         }
499         return SMB_VFS_NEXT_LLISTXATTR(handle, cappath, list, size);
500 }
501
502 static int cap_removexattr(vfs_handle_struct *handle, const char *path, const char *name)
503 {
504         char *cappath = capencode(talloc_tos(), path);
505         char *capname = capencode(talloc_tos(), name);
506
507         if (!cappath || !capname) {
508                 errno = ENOMEM;
509                 return -1;
510         }
511         return SMB_VFS_NEXT_REMOVEXATTR(handle, cappath, capname);
512 }
513
514 static int cap_lremovexattr(vfs_handle_struct *handle, const char *path, const char *name)
515 {
516         char *cappath = capencode(talloc_tos(), path);
517         char *capname = capencode(talloc_tos(), name);
518
519         if (!cappath || !capname) {
520                 errno = ENOMEM;
521                 return -1;
522         }
523         return SMB_VFS_NEXT_LREMOVEXATTR(handle, cappath, capname);
524 }
525
526 static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
527 {
528         char *cappath = capencode(talloc_tos(), path);
529
530         if (!cappath) {
531                 errno = ENOMEM;
532                 return -1;
533         }
534         return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
535 }
536
537 static int cap_setxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
538 {
539         char *cappath = capencode(talloc_tos(), path);
540         char *capname = capencode(talloc_tos(), name);
541
542         if (!cappath || !capname) {
543                 errno = ENOMEM;
544                 return -1;
545         }
546         return SMB_VFS_NEXT_SETXATTR(handle, cappath, capname, value, size, flags);
547 }
548
549 static int cap_lsetxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
550 {
551         char *cappath = capencode(talloc_tos(), path);
552         char *capname = capencode(talloc_tos(), name);
553
554         if (!cappath || !capname) {
555                 errno = ENOMEM;
556                 return -1;
557         }
558         return SMB_VFS_NEXT_LSETXATTR(handle, cappath, capname, value, size, flags);
559 }
560
561 static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
562 {
563         char *cappath = capencode(talloc_tos(), path);
564
565         if (!cappath) {
566                 errno = ENOMEM;
567                 return -1;
568         }
569         return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
570 }
571
572 static struct vfs_fn_pointers vfs_cap_fns = {
573         .disk_free = cap_disk_free,
574         .opendir = cap_opendir,
575         .readdir = cap_readdir,
576         .mkdir = cap_mkdir,
577         .rmdir = cap_rmdir,
578         .open = cap_open,
579         .rename = cap_rename,
580         .stat = cap_stat,
581         .lstat = cap_lstat,
582         .unlink = cap_unlink,
583         .chmod = cap_chmod,
584         .chown = cap_chown,
585         .lchown = cap_lchown,
586         .chdir = cap_chdir,
587         .ntimes = cap_ntimes,
588         .symlink = cap_symlink,
589         .vfs_readlink = cap_readlink,
590         .link = cap_link,
591         .mknod = cap_mknod,
592         .realpath = cap_realpath,
593         .chmod_acl = cap_chmod_acl,
594         .sys_acl_get_file = cap_sys_acl_get_file,
595         .sys_acl_set_file = cap_sys_acl_set_file,
596         .sys_acl_delete_def_file = cap_sys_acl_delete_def_file,
597         .getxattr = cap_getxattr,
598         .lgetxattr = cap_lgetxattr,
599         .fgetxattr = cap_fgetxattr,
600         .listxattr = cap_listxattr,
601         .llistxattr = cap_llistxattr,
602         .removexattr = cap_removexattr,
603         .lremovexattr = cap_lremovexattr,
604         .fremovexattr = cap_fremovexattr,
605         .setxattr = cap_setxattr,
606         .lsetxattr = cap_lsetxattr,
607         .fsetxattr = cap_fsetxattr
608 };
609
610 NTSTATUS vfs_cap_init(void);
611 NTSTATUS vfs_cap_init(void)
612 {
613         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "cap",
614                                 &vfs_cap_fns);
615 }
616
617 /* For CAP functions */
618 #define hex_tag ':'
619 #define hex2bin(c)              hex2bin_table[(unsigned char)(c)]
620 #define bin2hex(c)              bin2hex_table[(unsigned char)(c)]
621 #define is_hex(s)               ((s)[0] == hex_tag)
622
623 static unsigned char hex2bin_table[256] = {
624 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
625 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
626 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
627 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
628 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x40 */
629 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
630 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
631 0000, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0000, /* 0x60 */
632 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
633 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
634 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */
635 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */
636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */
637 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */
638 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */
639 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */
640 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */
641 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  /* 0xf0 */
642 };
643 static unsigned char bin2hex_table[256] = "0123456789abcdef";
644
645 /*******************************************************************
646   original code -> ":xx"  - CAP format
647 ********************************************************************/
648
649 static char *capencode(TALLOC_CTX *ctx, const char *from)
650 {
651         char *out = NULL;
652         const char *p1;
653         char *to = NULL;
654         size_t len = 0;
655
656         for (p1 = from; *p1; p1++) {
657                 if ((unsigned char)*p1 >= 0x80) {
658                         len += 3;
659                 } else {
660                         len++;
661                 }
662         }
663         len++;
664
665         to = TALLOC_ARRAY(ctx, char, len);
666         if (!to) {
667                 return NULL;
668         }
669
670         for (out = to; *from;) {
671                 /* buffer husoku error */
672                 if ((unsigned char)*from >= 0x80) {
673                         *out++ = hex_tag;
674                         *out++ = bin2hex (((*from)>>4)&0x0f);
675                         *out++ = bin2hex ((*from)&0x0f);
676                         from++;
677                 } else {
678                         *out++ = *from++;
679                 }
680         }
681         *out = '\0';
682         return to;
683 }
684
685 /*******************************************************************
686   CAP -> original code
687 ********************************************************************/
688 /* ":xx" -> a byte */
689
690 static char *capdecode(TALLOC_CTX *ctx, const char *from)
691 {
692         const char *p1;
693         char *out = NULL;
694         char *to = NULL;
695         size_t len = 0;
696
697         for (p1 = from; *p1; len++) {
698                 if (is_hex(p1)) {
699                         p1 += 3;
700                 } else {
701                         p1++;
702                 }
703         }
704         len++;
705
706         to = TALLOC_ARRAY(ctx, char, len);
707         if (!to) {
708                 return NULL;
709         }
710
711         for (out = to; *from;) {
712                 if (is_hex(from)) {
713                         *out++ = (hex2bin(from[1])<<4) | (hex2bin(from[2]));
714                         from += 3;
715                 } else {
716                         *out++ = *from++;
717                 }
718         }
719         *out = '\0';
720         return to;
721 }