librpc/ndr: Use converted_size to determine if NULL termination was sent
[samba.git] / librpc / ndr / ndr_string.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    routines for marshalling/unmarshalling string types
5
6    Copyright (C) Andrew Tridgell 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "librpc/ndr/libndr.h"
24
25 /**
26   pull a general string from the wire
27 */
28 _PUBLIC_ enum ndr_err_code ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
29 {
30         char *as=NULL;
31         uint32_t len1, ofs, len2;
32         uint16_t len3;
33         size_t conv_src_len = 0, converted_size;
34         int do_convert = 1, chset = CH_UTF16;
35         unsigned byte_mul = 2;
36         unsigned flags = ndr->flags;
37         unsigned c_len_term = 0;
38
39         if (!(ndr_flags & NDR_SCALARS)) {
40                 return NDR_ERR_SUCCESS;
41         }
42
43         if (NDR_BE(ndr)) {
44                 chset = CH_UTF16BE;
45         }
46
47         if (flags & LIBNDR_FLAG_STR_ASCII) {
48                 chset = CH_DOS;
49                 byte_mul = 1;
50                 flags &= ~LIBNDR_FLAG_STR_ASCII;
51         }
52
53         if (flags & LIBNDR_FLAG_STR_UTF8) {
54                 chset = CH_UTF8;
55                 byte_mul = 1;
56                 flags &= ~LIBNDR_FLAG_STR_UTF8;
57         }
58
59         if (flags & LIBNDR_FLAG_STR_RAW8) {
60                 do_convert = 0;
61                 byte_mul = 1;
62                 flags &= ~LIBNDR_FLAG_STR_RAW8;
63         }
64
65         flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
66         if (flags & LIBNDR_FLAG_STR_CHARLEN) {
67                 c_len_term = 1;
68                 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
69         }
70
71         switch (flags & LIBNDR_STRING_FLAGS) {
72         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
73         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
74                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
75                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
76                 if (ofs != 0) {
77                         return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
78                                               ndr->flags & LIBNDR_STRING_FLAGS);
79                 }
80                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
81                 if (len2 > len1) {
82                         return ndr_pull_error(ndr, NDR_ERR_STRING,
83                                               "Bad string lengths len1=%u ofs=%u len2=%u\n",
84                                               len1, ofs, len2);
85                 } else if (len1 != len2) {
86                         DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as));
87                 }
88                 conv_src_len = len2 + c_len_term;
89                 break;
90
91         case LIBNDR_FLAG_STR_SIZE4:
92         case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
93                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
94                 conv_src_len = len1 + c_len_term;
95                 break;
96
97         case LIBNDR_FLAG_STR_LEN4:
98         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
99                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
100                 if (ofs != 0) {
101                         return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
102                                               ndr->flags & LIBNDR_STRING_FLAGS);
103                 }
104                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
105                 conv_src_len = len1 + c_len_term;
106                 break;
107
108         case LIBNDR_FLAG_STR_SIZE2:
109         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
110                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
111                 conv_src_len = len3 + c_len_term;
112                 break;
113
114         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
115                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
116                 conv_src_len = len3;
117                 byte_mul = 1; /* the length is now absolute */
118                 break;
119
120         case LIBNDR_FLAG_STR_NULLTERM:
121                 if (byte_mul == 1) {
122                         conv_src_len = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
123                 } else {
124                         conv_src_len = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
125                 }
126                 byte_mul = 1; /* the length is now absolute */
127                 break;
128
129         case LIBNDR_FLAG_STR_NOTERM:
130                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
131                         return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
132                                               ndr->flags & LIBNDR_STRING_FLAGS);
133                 }
134                 conv_src_len = ndr->data_size - ndr->offset;
135                 byte_mul = 1; /* the length is now absolute */
136                 break;
137
138         default:
139                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
140                                       ndr->flags & LIBNDR_STRING_FLAGS);
141         }
142
143         NDR_PULL_NEED_BYTES(ndr, conv_src_len * byte_mul);
144         if (conv_src_len == 0) {
145                 as = talloc_strdup(ndr->current_mem_ctx, "");
146                 converted_size = 0;
147         } else {
148                 if (!do_convert) {
149                         as = talloc_strndup(ndr->current_mem_ctx,
150                                             ndr->data + ndr->offset,
151                                             conv_src_len);
152                         if (!as) {
153                                 return ndr_pull_error(ndr, NDR_ERR_ALLOC,
154                                                       "Failed to talloc_strndup() in RAW8 ndr_string_pull()");
155                         }
156                         converted_size = MIN(strlen(as)+1, conv_src_len);
157                 } else if (!convert_string_talloc(ndr->current_mem_ctx, chset,
158                                            CH_UNIX, ndr->data + ndr->offset,
159                                            conv_src_len * byte_mul,
160                                            (void **)(void *)&as,
161                                            &converted_size)) {
162                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
163                                               "Bad character conversion with flags 0x%x", flags);
164                 }
165         }
166
167         /* this is a way of detecting if a string is sent with the wrong
168            termination */
169         if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
170                 if (as && converted_size > 0 && as[converted_size-1] == '\0') {
171                         DEBUG(6,("short string '%s', sent with NULL termination despite NOTERM flag in IDL\n", as));
172                 }
173         } else {
174                 if (as && converted_size > 0 && as[converted_size-1] != '\0') {
175                         DEBUG(6,("long string '%s', send without NULL termination (which was expected)\n", as));
176                 }
177         }
178
179         NDR_CHECK(ndr_pull_advance(ndr, conv_src_len * byte_mul));
180         *s = as;
181
182         return NDR_ERR_SUCCESS;
183 }
184
185
186 /**
187   push a general string onto the wire
188 */
189 _PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
190 {
191         ssize_t s_len, c_len;
192         size_t d_len;
193         int do_convert = 1, chset = CH_UTF16;
194         unsigned flags = ndr->flags;
195         unsigned byte_mul = 2;
196         uint8_t *dest = NULL;
197
198         if (!(ndr_flags & NDR_SCALARS)) {
199                 return NDR_ERR_SUCCESS;
200         }
201
202         if (NDR_BE(ndr)) {
203                 chset = CH_UTF16BE;
204         }
205         
206         s_len = s?strlen(s):0;
207
208         if (flags & LIBNDR_FLAG_STR_ASCII) {
209                 chset = CH_DOS;
210                 byte_mul = 1;
211                 flags &= ~LIBNDR_FLAG_STR_ASCII;
212         }
213
214         if (flags & LIBNDR_FLAG_STR_UTF8) {
215                 chset = CH_UTF8;
216                 byte_mul = 1;
217                 flags &= ~LIBNDR_FLAG_STR_UTF8;
218         }
219
220         if (flags & LIBNDR_FLAG_STR_RAW8) {
221                 do_convert = 0;
222                 byte_mul = 1;
223                 flags &= ~LIBNDR_FLAG_STR_RAW8;
224         }
225
226         flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
227
228         if (!(flags & LIBNDR_FLAG_STR_NOTERM)) {
229                 s_len++;
230         }
231
232         if (!do_convert) {
233                 d_len = s_len;
234                 dest = talloc_strndup(ndr, s, s_len);
235         } else if (!convert_string_talloc(ndr, CH_UNIX, chset, s, s_len,
236                                    (void **)(void *)&dest, &d_len))
237         {
238                 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
239                                       "Bad character push conversion with flags 0x%x", flags);
240         }
241
242         if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
243                 c_len = d_len;
244                 flags &= ~LIBNDR_FLAG_STR_BYTESIZE;
245         } else if (flags & LIBNDR_FLAG_STR_CHARLEN) {
246                 c_len = (d_len / byte_mul)-1;
247                 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
248         } else {
249                 c_len = d_len / byte_mul;
250         }
251
252         switch ((flags & LIBNDR_STRING_FLAGS) & ~LIBNDR_FLAG_STR_NOTERM) {
253         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
254                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
255                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
256                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
257                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
258                 break;
259
260         case LIBNDR_FLAG_STR_LEN4:
261                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
262                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
263                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
264                 break;
265
266         case LIBNDR_FLAG_STR_SIZE4:
267                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
268                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
269                 break;
270
271         case LIBNDR_FLAG_STR_SIZE2:
272                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len));
273                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
274                 break;
275
276         case LIBNDR_FLAG_STR_NULLTERM:
277                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
278                 break;
279
280         default:
281                 if (ndr->flags & LIBNDR_FLAG_REMAINING) {
282                         NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
283                         break;          
284                 }
285
286                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
287                                       ndr->flags & LIBNDR_STRING_FLAGS);
288         }
289
290         talloc_free(dest);
291
292         return NDR_ERR_SUCCESS;
293 }
294
295 /**
296   push a general string onto the wire
297 */
298 _PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s)
299 {
300         size_t c_len;
301         unsigned flags = ndr->flags;
302         unsigned byte_mul = 2;
303         unsigned c_len_term = 1;
304
305         if (flags & LIBNDR_FLAG_STR_RAW8) {
306                 c_len = s?strlen(s):0;
307         } else {
308                 c_len = s?strlen_m(s):0;
309         }
310
311         if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_RAW8|LIBNDR_FLAG_STR_UTF8)) {
312                 byte_mul = 1;
313         }
314
315         if (flags & LIBNDR_FLAG_STR_NOTERM) {
316                 c_len_term = 0;
317         }
318
319         c_len = c_len + c_len_term;
320
321         if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
322                 c_len = c_len * byte_mul;
323         }
324
325         return c_len;
326 }
327
328 _PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
329 {
330         if (s) {
331                 ndr->print(ndr, "%-25s: '%s'", name, s);
332         } else {
333                 ndr->print(ndr, "%-25s: NULL", name);
334         }
335 }
336
337 _PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, int flags) 
338 {
339         /* FIXME: Is this correct for all strings ? */
340         if(!(*string)) return ret;
341         return ret+strlen(*string)+1;
342 }
343
344 /**
345   pull a general string array from the wire
346 */
347 _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a)
348 {
349         const char **a = NULL;
350         uint32_t count;
351         unsigned flags = ndr->flags;
352         unsigned saved_flags = ndr->flags;
353
354         if (!(ndr_flags & NDR_SCALARS)) {
355                 return NDR_ERR_SUCCESS;
356         }
357
358         switch (flags & (LIBNDR_FLAG_STR_NULLTERM|LIBNDR_FLAG_STR_NOTERM)) {
359         case LIBNDR_FLAG_STR_NULLTERM:
360                 /* 
361                  * here the strings are null terminated
362                  * but also the array is null terminated if LIBNDR_FLAG_REMAINING
363                  * is specified
364                  */
365                 for (count = 0;; count++) {
366                         TALLOC_CTX *tmp_ctx;
367                         const char *s = NULL;
368                         a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
369                         NDR_ERR_HAVE_NO_MEMORY(a);
370                         a[count]   = NULL;
371                         a[count+1]   = NULL;
372
373                         tmp_ctx = ndr->current_mem_ctx;
374                         ndr->current_mem_ctx = a;
375                         NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
376                         if ((ndr->data_size - ndr->offset) == 0 && ndr->flags & LIBNDR_FLAG_REMAINING)
377                         {
378                                 a[count] = s;
379                                 break;
380                         }
381                         ndr->current_mem_ctx = tmp_ctx;
382                         if (strcmp("", s)==0) {
383                                 a[count] = NULL;
384                                 break;
385                         } else {
386                                 a[count] = s;
387                         }
388                 }
389
390                 *_a =a;
391                 break;
392
393         case LIBNDR_FLAG_STR_NOTERM:
394                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
395                         return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
396                                               ndr->flags & LIBNDR_STRING_FLAGS);
397                 }
398                 /*
399                  * here the strings are not null terminated
400                  * but serarated by a null terminator
401                  *
402                  * which means the same as:
403                  * Every string is null terminated exept the last
404                  * string is terminated by the end of the buffer
405                  *
406                  * as LIBNDR_FLAG_STR_NULLTERM also end at the end
407                  * of the buffer, we can pull each string with this flag
408                  *
409                  * The big difference with the case LIBNDR_FLAG_STR_NOTERM +
410                  * LIBNDR_FLAG_REMAINING is that the last string will not be null terminated
411                  */
412                 ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
413                 ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
414
415                 for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) {
416                         TALLOC_CTX *tmp_ctx;
417                         const char *s = NULL;
418                         a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
419                         NDR_ERR_HAVE_NO_MEMORY(a);
420                         a[count]   = NULL;
421                         a[count+1]   = NULL;
422
423                         tmp_ctx = ndr->current_mem_ctx;
424                         ndr->current_mem_ctx = a;
425                         NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
426                         ndr->current_mem_ctx = tmp_ctx;
427                         a[count] = s;
428                 }
429
430                 *_a =a;
431                 break;
432
433         default:
434                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
435                                       ndr->flags & LIBNDR_STRING_FLAGS);
436         }
437
438         ndr->flags = saved_flags;
439         return NDR_ERR_SUCCESS;
440 }
441
442 /**
443   push a general string array onto the wire
444 */
445 _PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a)
446 {
447         uint32_t count;
448         unsigned flags = ndr->flags;
449         unsigned saved_flags = ndr->flags;
450
451         if (!(ndr_flags & NDR_SCALARS)) {
452                 return NDR_ERR_SUCCESS;
453         }
454
455         switch (flags & LIBNDR_STRING_FLAGS) {
456         case LIBNDR_FLAG_STR_NULLTERM:
457                 for (count = 0; a && a[count]; count++) {
458                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
459                 }
460                 /* If LIBNDR_FLAG_REMAINING then we do not add a null terminator to the array */
461                 if (!(flags & LIBNDR_FLAG_REMAINING))
462                 {
463                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
464                 }
465                 break;
466
467         case LIBNDR_FLAG_STR_NOTERM:
468                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
469                         return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
470                                               ndr->flags & LIBNDR_STRING_FLAGS);
471                 }
472
473                 for (count = 0; a && a[count]; count++) {
474                         if (count > 0) {
475                                 ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
476                                 ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
477                                 NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
478                                 ndr->flags = saved_flags;
479                         }
480                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
481                 }
482
483                 break;
484
485         default:
486                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
487                                       ndr->flags & LIBNDR_STRING_FLAGS);
488         }
489         
490         ndr->flags = saved_flags;
491         return NDR_ERR_SUCCESS;
492 }
493
494 _PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
495 {
496         uint32_t count;
497         uint32_t i;
498
499         for (count = 0; a && a[count]; count++) {}
500
501         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
502         ndr->depth++;
503         for (i=0;i<count;i++) {
504                 char *idx=NULL;
505                 if (asprintf(&idx, "[%d]", i) != -1) {
506                         ndr_print_string(ndr, idx, a[i]);
507                         free(idx);
508                 }
509         }
510         ndr->depth--;
511 }
512
513 _PUBLIC_ size_t ndr_size_string_array(const char **a, uint32_t count, int flags)
514 {
515         uint32_t i;
516         size_t size = 0;
517         int rawbytes = 0;
518
519         if (flags & LIBNDR_FLAG_STR_RAW8) {
520                 rawbytes = 1;
521                 flags &= ~LIBNDR_FLAG_STR_RAW8;
522         }
523
524         switch (flags & LIBNDR_STRING_FLAGS) {
525         case LIBNDR_FLAG_STR_NULLTERM:
526                 for (i = 0; i < count; i++) {
527                         size += rawbytes?strlen(a[i]) + 1:strlen_m_term(a[i]);
528                 }
529                 break;
530         case LIBNDR_FLAG_STR_NOTERM:
531                 for (i = 0; i < count; i++) {
532                         size += rawbytes?strlen(a[i]):strlen_m(a[i]);
533                 }
534                 break;
535         default:
536                 return 0;
537         }
538
539         return size;
540 }
541
542 /**
543  * Return number of elements in a string including the last (zeroed) element 
544  */
545 _PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size)
546 {
547         uint32_t i;
548         uint8_t zero[4] = {0,0,0,0};
549         const char *var = (const char *)_var;
550
551         for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
552
553         return i+1;
554 }
555
556 _PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size)
557 {
558         uint32_t i;
559         uint32_t save_offset;
560
561         save_offset = ndr->offset;
562         ndr_pull_advance(ndr, (count - 1) * element_size);
563         NDR_PULL_NEED_BYTES(ndr, element_size);
564
565         for (i = 0; i < element_size; i++) {
566                  if (ndr->data[ndr->offset+i] != 0) {
567                         ndr->offset = save_offset;
568
569                         return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries");
570                  }
571         }
572
573         ndr->offset = save_offset;
574
575         return NDR_ERR_SUCCESS;
576 }
577
578 _PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset)
579 {
580         size_t converted_size;
581
582         if (length == 0) {
583                 *var = talloc_strdup(ndr->current_mem_ctx, "");
584                 return NDR_ERR_SUCCESS;
585         }
586
587         if (NDR_BE(ndr) && chset == CH_UTF16) {
588                 chset = CH_UTF16BE;
589         }
590
591         NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
592
593         if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
594                                    ndr->data+ndr->offset, length*byte_mul,
595                                    discard_const_p(void *, var),
596                                    &converted_size))
597         {
598                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
599                                       "Bad character conversion");
600         }
601         NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
602
603         return NDR_ERR_SUCCESS;
604 }
605
606 _PUBLIC_ enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset)
607 {
608         ssize_t required;
609
610         if (NDR_BE(ndr) && chset == CH_UTF16) {
611                 chset = CH_UTF16BE;
612         }
613
614         required = byte_mul * length;
615         
616         NDR_PUSH_NEED_BYTES(ndr, required);
617
618         if (required) {
619                 size_t size = 0;
620                 if (!convert_string(CH_UNIX, chset,
621                              var, strlen(var),
622                              ndr->data+ndr->offset, required, &size)) {
623                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
624                                       "Bad character conversion");
625                 }
626
627                 /* Make sure the remaining part of the string is filled with zeroes */
628                 if (size < required) {
629                         memset(ndr->data+ndr->offset+size, 0, required-size);
630                 }
631         }
632
633         ndr->offset += required;
634
635         return NDR_ERR_SUCCESS;
636 }
637
638 /* Return number of elements in a string in the specified charset */
639 _PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset)
640 {
641         switch (chset) {
642         /* case CH_UTF16: this has the same value as CH_UTF16LE */
643         case CH_UTF16LE:
644         case CH_UTF16BE:
645         case CH_UTF16MUNGED:
646         case CH_UTF8:
647                 return strlen_m_ext_term((const char *)var, CH_UNIX, chset);
648         case CH_DISPLAY:
649         case CH_DOS:
650         case CH_UNIX:
651                 return strlen((const char *)var)+1;
652         }
653
654         /* Fallback, this should never happen */
655         return strlen((const char *)var)+1;
656 }