5863d72f38059fb611db20de83b06e84be1611df
[kai/samba.git] / source3 / lib / charcnv.c
1 /*
2    Unix SMB/CIFS implementation.
3    Character set conversion Extensions
4    Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
5    Copyright (C) Andrew Tridgell 2001
6    Copyright (C) Simo Sorce 2001
7    Copyright (C) Martin Pool 2003
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22 */
23 #include "includes.h"
24
25 /**
26  * Destroy global objects allocated by init_iconv()
27  **/
28 void gfree_charcnv(void)
29 {
30         TALLOC_FREE(global_iconv_handle);
31 }
32
33 /**
34  * Copy a string from a char* unix src to a dos codepage string destination.
35  *
36  * @return the number of bytes occupied by the string in the destination.
37  *
38  * @param flags can include
39  * <dl>
40  * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
41  * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
42  * </dl>
43  *
44  * @param dest_len the maximum length in bytes allowed in the
45  * destination.
46  **/
47 size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
48 {
49         size_t src_len = strlen(src);
50         char *tmpbuf = NULL;
51         size_t size;
52         bool ret;
53
54         /* No longer allow a length of -1. */
55         if (dest_len == (size_t)-1) {
56                 smb_panic("push_ascii - dest_len == -1");
57         }
58
59         if (flags & STR_UPPER) {
60                 tmpbuf = SMB_STRDUP(src);
61                 if (!tmpbuf) {
62                         smb_panic("malloc fail");
63                 }
64                 strupper_m(tmpbuf);
65                 src = tmpbuf;
66         }
67
68         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
69                 src_len++;
70         }
71
72         ret = convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, &size);
73         if (ret == false &&
74                         (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
75                         && dest_len > 0) {
76                 ((char *)dest)[0] = '\0';
77         }
78         SAFE_FREE(tmpbuf);
79         return ret ? size : (size_t)-1;
80 }
81
82 /********************************************************************
83  Push and malloc an ascii string. src and dest null terminated.
84 ********************************************************************/
85
86 /**
87  * Copy a string from a dos codepage source to a unix char* destination.
88  *
89  * The resulting string in "dest" is always null terminated.
90  *
91  * @param flags can have:
92  * <dl>
93  * <dt>STR_TERMINATE</dt>
94  * <dd>STR_TERMINATE means the string in @p src
95  * is null terminated, and src_len is ignored.</dd>
96  * </dl>
97  *
98  * @param src_len is the length of the source area in bytes.
99  * @returns the number of bytes occupied by the string in @p src.
100  **/
101 size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
102 {
103         bool ret;
104         size_t size = 0;
105
106         if (dest_len == (size_t)-1) {
107                 /* No longer allow dest_len of -1. */
108                 smb_panic("pull_ascii - invalid dest_len of -1");
109         }
110
111         if (flags & STR_TERMINATE) {
112                 if (src_len == (size_t)-1) {
113                         src_len = strlen((const char *)src) + 1;
114                 } else {
115                         size_t len = strnlen((const char *)src, src_len);
116                         if (len < src_len)
117                                 len++;
118                         src_len = len;
119                 }
120         }
121
122         ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, &size);
123         if (ret == false) {
124                 size = 0;
125                 dest_len = 0;
126         }
127
128         if (dest_len && size) {
129                 /* Did we already process the terminating zero ? */
130                 if (dest[MIN(size-1, dest_len-1)] != 0) {
131                         dest[MIN(size, dest_len-1)] = 0;
132                 }
133         } else  {
134                 dest[0] = 0;
135         }
136
137         return src_len;
138 }
139
140 /**
141  * Copy a string from a dos codepage source to a unix char* destination.
142  * Talloc version.
143  *
144  * The resulting string in "dest" is always null terminated.
145  *
146  * @param flags can have:
147  * <dl>
148  * <dt>STR_TERMINATE</dt>
149  * <dd>STR_TERMINATE means the string in @p src
150  * is null terminated, and src_len is ignored.</dd>
151  * </dl>
152  *
153  * @param src_len is the length of the source area in bytes.
154  * @returns the number of bytes occupied by the string in @p src.
155  **/
156
157 static size_t pull_ascii_base_talloc(TALLOC_CTX *ctx,
158                                      char **ppdest,
159                                      const void *src,
160                                      size_t src_len,
161                                      int flags)
162 {
163         char *dest = NULL;
164         size_t dest_len;
165
166         *ppdest = NULL;
167
168         if (!src_len) {
169                 return 0;
170         }
171
172         if (src_len == (size_t)-1) {
173                 smb_panic("sec_len == -1 in pull_ascii_base_talloc");
174         }
175
176         if (flags & STR_TERMINATE) {
177                 size_t len = strnlen((const char *)src, src_len);
178                 if (len < src_len)
179                         len++;
180                 src_len = len;
181                 /* Ensure we don't use an insane length from the client. */
182                 if (src_len >= 1024*1024) {
183                         char *msg = talloc_asprintf(ctx,
184                                         "Bad src length (%u) in "
185                                         "pull_ascii_base_talloc",
186                                         (unsigned int)src_len);
187                         smb_panic(msg);
188                 }
189         }
190
191         /* src_len != -1 here. */
192
193         if (!convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len, &dest,
194                                      &dest_len)) {
195                 dest_len = 0;
196         }
197
198         if (dest_len && dest) {
199                 /* Did we already process the terminating zero ? */
200                 if (dest[dest_len-1] != 0) {
201                         size_t size = talloc_get_size(dest);
202                         /* Have we got space to append the '\0' ? */
203                         if (size <= dest_len) {
204                                 /* No, realloc. */
205                                 dest = talloc_realloc(ctx, dest, char,
206                                                 dest_len+1);
207                                 if (!dest) {
208                                         /* talloc fail. */
209                                         dest_len = (size_t)-1;
210                                         return 0;
211                                 }
212                         }
213                         /* Yay - space ! */
214                         dest[dest_len] = '\0';
215                         dest_len++;
216                 }
217         } else if (dest) {
218                 dest[0] = 0;
219         }
220
221         *ppdest = dest;
222         return src_len;
223 }
224
225 /**
226  * Copy a string from a char* src to a unicode destination.
227  *
228  * @returns the number of bytes occupied by the string in the destination.
229  *
230  * @param flags can have:
231  *
232  * <dl>
233  * <dt>STR_TERMINATE <dd>means include the null termination.
234  * <dt>STR_UPPER     <dd>means uppercase in the destination.
235  * <dt>STR_NOALIGN   <dd>means don't do alignment.
236  * </dl>
237  *
238  * @param dest_len is the maximum length allowed in the
239  * destination.
240  **/
241
242 static size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
243 {
244         size_t len=0;
245         size_t src_len;
246         size_t size = 0;
247         bool ret;
248
249         if (dest_len == (size_t)-1) {
250                 /* No longer allow dest_len of -1. */
251                 smb_panic("push_ucs2 - invalid dest_len of -1");
252         }
253
254         if (flags & STR_TERMINATE)
255                 src_len = (size_t)-1;
256         else
257                 src_len = strlen(src);
258
259         if (ucs2_align(base_ptr, dest, flags)) {
260                 *(char *)dest = 0;
261                 dest = (void *)((char *)dest + 1);
262                 if (dest_len)
263                         dest_len--;
264                 len++;
265         }
266
267         /* ucs2 is always a multiple of 2 bytes */
268         dest_len &= ~1;
269
270         ret = convert_string(CH_UNIX, CH_UTF16LE, src, src_len, dest, dest_len, &size);
271         if (ret == false) {
272                 if ((flags & STR_TERMINATE) &&
273                                 dest &&
274                                 dest_len) {
275                         *(char *)dest = 0;
276                 }
277                 return len;
278         }
279
280         len += size;
281
282         if (flags & STR_UPPER) {
283                 smb_ucs2_t *dest_ucs2 = (smb_ucs2_t *)dest;
284                 size_t i;
285
286                 /* We check for i < (ret / 2) below as the dest string isn't null
287                    terminated if STR_TERMINATE isn't set. */
288
289                 for (i = 0; i < (ret / 2) && i < (dest_len / 2) && dest_ucs2[i]; i++) {
290                         smb_ucs2_t v = toupper_w(dest_ucs2[i]);
291                         if (v != dest_ucs2[i]) {
292                                 dest_ucs2[i] = v;
293                         }
294                 }
295         }
296
297         return len;
298 }
299
300 /**
301  Copy a string from a ucs2 source to a unix char* destination.
302  Talloc version with a base pointer.
303  Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
304  needs fixing. JRA).
305  Flags can have:
306   STR_TERMINATE means the string in src is null terminated.
307   STR_NOALIGN   means don't try to align.
308  if STR_TERMINATE is set then src_len is ignored if it is -1.
309  src_len is the length of the source area in bytes
310  Return the number of bytes occupied by the string in src.
311  The resulting string in "dest" is always null terminated.
312 **/
313
314 static size_t pull_ucs2_base_talloc(TALLOC_CTX *ctx,
315                                     const void *base_ptr,
316                                     char **ppdest,
317                                     const void *src,
318                                     size_t src_len,
319                                     int flags)
320 {
321         char *dest;
322         size_t dest_len;
323         size_t ucs2_align_len = 0;
324
325         *ppdest = NULL;
326
327 #ifdef DEVELOPER
328         /* Ensure we never use the braindead "malloc" varient. */
329         if (ctx == NULL) {
330                 smb_panic("NULL talloc CTX in pull_ucs2_base_talloc\n");
331         }
332 #endif
333
334         if (!src_len) {
335                 return 0;
336         }
337
338         if (src_len == (size_t)-1) {
339                 /* no longer used anywhere, but worth checking */
340                 smb_panic("sec_len == -1 in pull_ucs2_base_talloc");
341         }
342
343         if (ucs2_align(base_ptr, src, flags)) {
344                 src = (const void *)((const char *)src + 1);
345                 src_len--;
346                 ucs2_align_len = 1;
347         }
348
349         if (flags & STR_TERMINATE) {
350                 /* src_len -1 is the default for null terminated strings. */
351                 size_t len = strnlen_w((const smb_ucs2_t *)src,
352                                        src_len/2);
353                 if (len < src_len/2)
354                         len++;
355                 src_len = len*2;
356
357                 /* Ensure we don't use an insane length from the client. */
358                 if (src_len >= 1024*1024) {
359                         smb_panic("Bad src length in pull_ucs2_base_talloc\n");
360                 }
361         }
362
363         /* ucs2 is always a multiple of 2 bytes */
364         src_len &= ~1;
365
366         if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
367                                    (void *)&dest, &dest_len)) {
368                 dest_len = 0;
369         }
370
371         if (dest_len) {
372                 /* Did we already process the terminating zero ? */
373                 if (dest[dest_len-1] != 0) {
374                         size_t size = talloc_get_size(dest);
375                         /* Have we got space to append the '\0' ? */
376                         if (size <= dest_len) {
377                                 /* No, realloc. */
378                                 dest = talloc_realloc(ctx, dest, char,
379                                                 dest_len+1);
380                                 if (!dest) {
381                                         /* talloc fail. */
382                                         dest_len = (size_t)-1;
383                                         return 0;
384                                 }
385                         }
386                         /* Yay - space ! */
387                         dest[dest_len] = '\0';
388                         dest_len++;
389                 }
390         } else if (dest) {
391                 dest[0] = 0;
392         }
393
394         *ppdest = dest;
395         return src_len + ucs2_align_len;
396 }
397
398 /**
399  Copy a string from a char* src to a unicode or ascii
400  dos codepage destination choosing unicode or ascii based on the 
401  flags supplied
402  Return the number of bytes occupied by the string in the destination.
403  flags can have:
404   STR_TERMINATE means include the null termination.
405   STR_UPPER     means uppercase in the destination.
406   STR_ASCII     use ascii even with unicode packet.
407   STR_NOALIGN   means don't do alignment.
408  dest_len is the maximum length allowed in the destination. If dest_len
409  is -1 then no maxiumum is used.
410 **/
411
412 size_t push_string_check_fn(void *dest, const char *src,
413                          size_t dest_len, int flags)
414 {
415         if (!(flags & STR_ASCII) && (flags & STR_UNICODE)) {
416                 return push_ucs2(NULL, dest, src, dest_len, flags);
417         }
418         return push_ascii(dest, src, dest_len, flags);
419 }
420
421
422 /**
423  Copy a string from a char* src to a unicode or ascii
424  dos codepage destination choosing unicode or ascii based on the 
425  flags in the SMB buffer starting at base_ptr.
426  Return the number of bytes occupied by the string in the destination.
427  flags can have:
428   STR_TERMINATE means include the null termination.
429   STR_UPPER     means uppercase in the destination.
430   STR_ASCII     use ascii even with unicode packet.
431   STR_NOALIGN   means don't do alignment.
432  dest_len is the maximum length allowed in the destination. If dest_len
433  is -1 then no maxiumum is used.
434 **/
435
436 size_t push_string_base(const char *base, uint16 flags2,
437                         void *dest, const char *src,
438                         size_t dest_len, int flags)
439 {
440
441         if (!(flags & STR_ASCII) && \
442             ((flags & STR_UNICODE || \
443               (flags2 & FLAGS2_UNICODE_STRINGS)))) {
444                 return push_ucs2(base, dest, src, dest_len, flags);
445         }
446         return push_ascii(dest, src, dest_len, flags);
447 }
448
449 /**
450  Copy a string from a unicode or ascii source (depending on
451  the packet flags) to a char* destination.
452  Variant that uses talloc.
453  Flags can have:
454   STR_TERMINATE means the string in src is null terminated.
455   STR_UNICODE   means to force as unicode.
456   STR_ASCII     use ascii even with unicode packet.
457   STR_NOALIGN   means don't do alignment.
458  if STR_TERMINATE is set then src_len is ignored is it is -1
459  src_len is the length of the source area in bytes.
460  Return the number of bytes occupied by the string in src.
461  The resulting string in "dest" is always null terminated.
462 **/
463
464 size_t pull_string_talloc(TALLOC_CTX *ctx,
465                           const void *base_ptr,
466                           uint16 smb_flags2,
467                           char **ppdest,
468                           const void *src,
469                           size_t src_len,
470                           int flags)
471 {
472         if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
473                 smb_panic("No base ptr to get flg2 and neither ASCII nor "
474                           "UNICODE defined");
475         }
476
477         if (!(flags & STR_ASCII) && \
478             ((flags & STR_UNICODE || \
479               (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
480                 return pull_ucs2_base_talloc(ctx,
481                                         base_ptr,
482                                         ppdest,
483                                         src,
484                                         src_len,
485                                         flags);
486         }
487         return pull_ascii_base_talloc(ctx,
488                                         ppdest,
489                                         src,
490                                         src_len,
491                                         flags);
492 }
493
494
495 size_t align_string(const void *base_ptr, const char *p, int flags)
496 {
497         if (!(flags & STR_ASCII) && \
498             ((flags & STR_UNICODE || \
499               (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
500                 return ucs2_align(base_ptr, p, flags);
501         }
502         return 0;
503 }
504
505 /*******************************************************************
506  Write a string in (little-endian) unicode format. src is in
507  the current DOS codepage. len is the length in bytes of the
508  string pointed to by dst.
509
510  if null_terminate is True then null terminate the packet (adds 2 bytes)
511
512  the return value is the length in bytes consumed by the string, including the
513  null termination if applied
514 ********************************************************************/
515
516 size_t dos_PutUniCode(char *dst,const char *src, size_t len, bool null_terminate)
517 {
518         int flags = null_terminate ? STR_UNICODE|STR_NOALIGN|STR_TERMINATE
519                                    : STR_UNICODE|STR_NOALIGN;
520         return push_ucs2(NULL, dst, src, len, flags);
521 }
522
523
524 /* Converts a string from internal samba format to unicode. Always terminates.
525  * Actually just a wrapper round push_ucs2_talloc().
526  */
527
528 int rpcstr_push_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src)
529 {
530         size_t size;
531         if (push_ucs2_talloc(ctx, dest, src, &size))
532                 return size;
533         else
534                 return -1;
535 }