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