charcnv: removed the allow_badcharcnv and allow_bad_conv options to convert_string*()
[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 converted_size;
34         int 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         flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
60         if (flags & LIBNDR_FLAG_STR_CHARLEN) {
61                 c_len_term = 1;
62                 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
63         }
64
65         switch (flags & LIBNDR_STRING_FLAGS) {
66         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
67         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
68                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
69                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
70                 if (ofs != 0) {
71                         return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
72                                               ndr->flags & LIBNDR_STRING_FLAGS);
73                 }
74                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
75                 if (len2 > len1) {
76                         return ndr_pull_error(ndr, NDR_ERR_STRING, 
77                                               "Bad string lengths len1=%u ofs=%u len2=%u\n", 
78                                               len1, ofs, len2);
79                 }
80                 NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul);
81                 if (len2 == 0) {
82                         as = talloc_strdup(ndr->current_mem_ctx, "");
83                 } else {
84                         if (!convert_string_talloc(ndr->current_mem_ctx, chset,
85                                                    CH_UNIX,
86                                                    ndr->data+ndr->offset,
87                                                    (len2 + c_len_term)*byte_mul,
88                                                    (void **)(void *)&as,
89                                                    &converted_size))
90                         {
91                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
92                                                       "Bad character conversion with flags 0x%x", flags);
93                         }
94                 }
95                 NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul));
96
97                 if (len1 != len2) {
98                         DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as));
99                 }
100
101                 /* this is a way of detecting if a string is sent with the wrong
102                    termination */
103                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
104                         if (strlen(as) < (len2 + c_len_term)) {
105                                 DEBUG(6,("short string '%s'\n", as));
106                         }
107                 } else {
108                         if (strlen(as) == (len2 + c_len_term)) {
109                                 DEBUG(6,("long string '%s'\n", as));
110                         }
111                 }
112                 *s = as;
113                 break;
114
115         case LIBNDR_FLAG_STR_SIZE4:
116         case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
117                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
118                 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
119                 if (len1 == 0) {
120                         as = talloc_strdup(ndr->current_mem_ctx, "");
121                 } else {
122                         if (!convert_string_talloc(ndr->current_mem_ctx, chset,
123                                                    CH_UNIX,
124                                                    ndr->data+ndr->offset,
125                                                    (len1 + c_len_term)*byte_mul,
126                                                    (void **)(void *)&as,
127                                                    &converted_size))
128                         {
129                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
130                                                       "Bad character conversion with flags 0x%x", flags);
131                         }
132                 }
133                 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
134
135                 /* this is a way of detecting if a string is sent with the wrong
136                    termination */
137                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
138                         if (strlen(as) < (len1 + c_len_term)) {
139                                 DEBUG(6,("short string '%s'\n", as));
140                         }
141                 } else {
142                         if (strlen(as) == (len1 + c_len_term)) {
143                                 DEBUG(6,("long string '%s'\n", as));
144                         }
145                 }
146                 *s = as;
147                 break;
148
149         case LIBNDR_FLAG_STR_LEN4:
150         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
151                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
152                 if (ofs != 0) {
153                         return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
154                                               ndr->flags & LIBNDR_STRING_FLAGS);
155                 }
156                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
157                 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
158                 if (len1 == 0) {
159                         as = talloc_strdup(ndr->current_mem_ctx, "");
160                 } else {
161                         if (!convert_string_talloc(ndr->current_mem_ctx, chset,
162                                                    CH_UNIX,
163                                                    ndr->data+ndr->offset,
164                                                    (len1 + c_len_term)*byte_mul,
165                                                    (void **)(void *)&as,
166                                                    &converted_size))
167                         {
168                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
169                                                       "Bad character conversion with flags 0x%x", flags);
170                         }
171                 }
172                 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
173
174                 /* this is a way of detecting if a string is sent with the wrong
175                    termination */
176                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
177                         if (strlen(as) < (len1 + c_len_term)) {
178                                 DEBUG(6,("short string '%s'\n", as));
179                         }
180                 } else {
181                         if (strlen(as) == (len1 + c_len_term)) {
182                                 DEBUG(6,("long string '%s'\n", as));
183                         }
184                 }
185                 *s = as;
186                 break;
187
188
189         case LIBNDR_FLAG_STR_SIZE2:
190         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
191                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
192                 NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul);
193                 if (len3 == 0) {
194                         as = talloc_strdup(ndr->current_mem_ctx, "");
195                 } else {
196                         if (!convert_string_talloc(ndr->current_mem_ctx, chset,
197                                                    CH_UNIX,
198                                                    ndr->data+ndr->offset,
199                                                    (len3 + c_len_term)*byte_mul,
200                                                    (void **)(void *)&as,
201                                                    &converted_size))
202                         {
203                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
204                                                       "Bad character conversion with flags 0x%x", flags);
205                         }
206                 }
207                 NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul));
208
209                 /* this is a way of detecting if a string is sent with the wrong
210                    termination */
211                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
212                         if (strlen(as) < (len3 + c_len_term)) {
213                                 DEBUG(6,("short string '%s'\n", as));
214                         }
215                 } else {
216                         if (strlen(as) == (len3 + c_len_term)) {
217                                 DEBUG(6,("long string '%s'\n", as));
218                         }
219                 }
220                 *s = as;
221                 break;
222
223         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
224                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
225                 NDR_PULL_NEED_BYTES(ndr, len3);
226                 if (len3 == 0) {
227                         as = talloc_strdup(ndr->current_mem_ctx, "");
228                 } else {
229                         if (!convert_string_talloc(ndr->current_mem_ctx, chset,
230                                                    CH_UNIX,
231                                                    ndr->data+ndr->offset, len3,
232                                                    (void **)(void *)&as,
233                                                    &converted_size))
234                         {
235                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
236                                                       "Bad character conversion with flags 0x%x", flags);
237                         }
238                 }
239                 NDR_CHECK(ndr_pull_advance(ndr, len3));
240                 *s = as;
241                 break;
242
243         case LIBNDR_FLAG_STR_NULLTERM:
244                 if (byte_mul == 1) {
245                         len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
246                 } else {
247                         len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
248                 }
249                 if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
250                                            ndr->data+ndr->offset, len1,
251                                            (void **)(void *)&as,
252                                            &converted_size))
253                 {
254                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
255                                               "Bad character conversion with flags 0x%x", flags);
256                 }
257                 NDR_CHECK(ndr_pull_advance(ndr, len1));
258                 *s = as;
259                 break;
260
261         case LIBNDR_FLAG_STR_NOTERM:
262                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
263                         return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
264                                               ndr->flags & LIBNDR_STRING_FLAGS);
265                 }
266
267                 len1 = ndr->data_size - ndr->offset;
268
269                 NDR_PULL_NEED_BYTES(ndr, len1);
270                 if (len1 == 0) {
271                         as = talloc_strdup(ndr->current_mem_ctx, "");
272                 } else {
273                         if (!convert_string_talloc(ndr->current_mem_ctx, chset,
274                                                    CH_UNIX,
275                                                    ndr->data+ndr->offset, len1,
276                                                    (void **)(void *)&as,
277                                                    &converted_size))
278                         {
279                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
280                                                       "Bad character conversion with flags 0x%x", flags);
281                         }
282                 }
283                 NDR_CHECK(ndr_pull_advance(ndr, len1));
284
285                 *s = as;
286                 break;
287
288         default:
289                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
290                                       ndr->flags & LIBNDR_STRING_FLAGS);
291         }
292
293         return NDR_ERR_SUCCESS;
294 }
295
296
297 /**
298   push a general string onto the wire
299 */
300 _PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
301 {
302         ssize_t s_len, c_len;
303         size_t d_len;
304         int chset = CH_UTF16;
305         unsigned flags = ndr->flags;
306         unsigned byte_mul = 2;
307         uint8_t *dest = NULL;
308
309         if (!(ndr_flags & NDR_SCALARS)) {
310                 return NDR_ERR_SUCCESS;
311         }
312
313         if (NDR_BE(ndr)) {
314                 chset = CH_UTF16BE;
315         }
316         
317         s_len = s?strlen(s):0;
318
319         if (flags & LIBNDR_FLAG_STR_ASCII) {
320                 chset = CH_DOS;
321                 byte_mul = 1;
322                 flags &= ~LIBNDR_FLAG_STR_ASCII;
323         }
324
325         if (flags & LIBNDR_FLAG_STR_UTF8) {
326                 chset = CH_UTF8;
327                 byte_mul = 1;
328                 flags &= ~LIBNDR_FLAG_STR_UTF8;
329         }
330
331         flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
332
333         if (!(flags & LIBNDR_FLAG_STR_NOTERM)) {
334                 s_len++;
335         }
336         if (!convert_string_talloc(ndr, CH_UNIX, chset, s, s_len,
337                                    (void **)(void *)&dest, &d_len))
338         {
339                 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
340                                       "Bad character push conversion with flags 0x%x", flags);
341         }
342
343         if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
344                 c_len = d_len;
345                 flags &= ~LIBNDR_FLAG_STR_BYTESIZE;
346         } else if (flags & LIBNDR_FLAG_STR_CHARLEN) {
347                 c_len = (d_len / byte_mul)-1;
348                 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
349         } else {
350                 c_len = d_len / byte_mul;
351         }
352
353         switch ((flags & LIBNDR_STRING_FLAGS) & ~LIBNDR_FLAG_STR_NOTERM) {
354         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
355                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
356                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
357                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
358                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
359                 break;
360
361         case LIBNDR_FLAG_STR_LEN4:
362                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
363                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
364                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
365                 break;
366
367         case LIBNDR_FLAG_STR_SIZE4:
368                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
369                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
370                 break;
371
372         case LIBNDR_FLAG_STR_SIZE2:
373                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len));
374                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
375                 break;
376
377         case LIBNDR_FLAG_STR_NULLTERM:
378                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
379                 break;
380
381         default:
382                 if (ndr->flags & LIBNDR_FLAG_REMAINING) {
383                         NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
384                         break;          
385                 }
386
387                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
388                                       ndr->flags & LIBNDR_STRING_FLAGS);
389         }
390
391         talloc_free(dest);
392
393         return NDR_ERR_SUCCESS;
394 }
395
396 /**
397   push a general string onto the wire
398 */
399 _PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s)
400 {
401         size_t c_len;
402         unsigned flags = ndr->flags;
403         unsigned byte_mul = 2;
404         unsigned c_len_term = 1;
405
406         c_len = s?strlen_m(s):0;
407
408         if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_UTF8)) {
409                 byte_mul = 1;
410         }
411
412         if (flags & LIBNDR_FLAG_STR_NOTERM) {
413                 c_len_term = 0;
414         }
415
416         c_len = c_len + c_len_term;
417
418         if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
419                 c_len = c_len * byte_mul;
420         }
421
422         return c_len;
423 }
424
425 _PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
426 {
427         if (s) {
428                 ndr->print(ndr, "%-25s: '%s'", name, s);
429         } else {
430                 ndr->print(ndr, "%-25s: NULL", name);
431         }
432 }
433
434 _PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, int flags) 
435 {
436         /* FIXME: Is this correct for all strings ? */
437         if(!(*string)) return ret;
438         return ret+strlen(*string)+1;
439 }
440
441 /**
442   pull a general string array from the wire
443 */
444 _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a)
445 {
446         const char **a = NULL;
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_FLAG_STR_NULLTERM|LIBNDR_FLAG_STR_NOTERM)) {
456         case LIBNDR_FLAG_STR_NULLTERM:
457                 /* 
458                  * here the strings are null terminated
459                  * but also the array is null terminated if LIBNDR_FLAG_REMAINING
460                  * is specified
461                  */
462                 for (count = 0;; count++) {
463                         TALLOC_CTX *tmp_ctx;
464                         const char *s = NULL;
465                         a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
466                         NDR_ERR_HAVE_NO_MEMORY(a);
467                         a[count]   = NULL;
468                         a[count+1]   = NULL;
469
470                         tmp_ctx = ndr->current_mem_ctx;
471                         ndr->current_mem_ctx = a;
472                         NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
473                         if ((ndr->data_size - ndr->offset) == 0 && ndr->flags & LIBNDR_FLAG_REMAINING)
474                         {
475                                 a[count] = s;
476                                 break;
477                         }
478                         ndr->current_mem_ctx = tmp_ctx;
479                         if (strcmp("", s)==0) {
480                                 a[count] = NULL;
481                                 break;
482                         } else {
483                                 a[count] = s;
484                         }
485                 }
486
487                 *_a =a;
488                 break;
489
490         case LIBNDR_FLAG_STR_NOTERM:
491                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
492                         return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
493                                               ndr->flags & LIBNDR_STRING_FLAGS);
494                 }
495                 /*
496                  * here the strings are not null terminated
497                  * but serarated by a null terminator
498                  *
499                  * which means the same as:
500                  * Every string is null terminated exept the last
501                  * string is terminated by the end of the buffer
502                  *
503                  * as LIBNDR_FLAG_STR_NULLTERM also end at the end
504                  * of the buffer, we can pull each string with this flag
505                  *
506                  * The big difference with the case LIBNDR_FLAG_STR_NOTERM +
507                  * LIBNDR_FLAG_REMAINING is that the last string will not be null terminated
508                  */
509                 ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
510                 ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
511
512                 for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) {
513                         TALLOC_CTX *tmp_ctx;
514                         const char *s = NULL;
515                         a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
516                         NDR_ERR_HAVE_NO_MEMORY(a);
517                         a[count]   = NULL;
518                         a[count+1]   = NULL;
519
520                         tmp_ctx = ndr->current_mem_ctx;
521                         ndr->current_mem_ctx = a;
522                         NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
523                         ndr->current_mem_ctx = tmp_ctx;
524                         a[count] = s;
525                 }
526
527                 *_a =a;
528                 break;
529
530         default:
531                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
532                                       ndr->flags & LIBNDR_STRING_FLAGS);
533         }
534
535         ndr->flags = saved_flags;
536         return NDR_ERR_SUCCESS;
537 }
538
539 /**
540   push a general string array onto the wire
541 */
542 _PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a)
543 {
544         uint32_t count;
545         unsigned flags = ndr->flags;
546         unsigned saved_flags = ndr->flags;
547
548         if (!(ndr_flags & NDR_SCALARS)) {
549                 return NDR_ERR_SUCCESS;
550         }
551
552         switch (flags & LIBNDR_STRING_FLAGS) {
553         case LIBNDR_FLAG_STR_NULLTERM:
554                 for (count = 0; a && a[count]; count++) {
555                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
556                 }
557                 /* If LIBNDR_FLAG_REMAINING then we do not add a null terminator to the array */
558                 if (!(flags & LIBNDR_FLAG_REMAINING))
559                 {
560                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
561                 }
562                 break;
563
564         case LIBNDR_FLAG_STR_NOTERM:
565                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
566                         return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
567                                               ndr->flags & LIBNDR_STRING_FLAGS);
568                 }
569
570                 for (count = 0; a && a[count]; count++) {
571                         if (count > 0) {
572                                 ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
573                                 ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
574                                 NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
575                                 ndr->flags = saved_flags;
576                         }
577                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
578                 }
579
580                 break;
581
582         default:
583                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
584                                       ndr->flags & LIBNDR_STRING_FLAGS);
585         }
586         
587         ndr->flags = saved_flags;
588         return NDR_ERR_SUCCESS;
589 }
590
591 _PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
592 {
593         uint32_t count;
594         uint32_t i;
595
596         for (count = 0; a && a[count]; count++) {}
597
598         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
599         ndr->depth++;
600         for (i=0;i<count;i++) {
601                 char *idx=NULL;
602                 if (asprintf(&idx, "[%d]", i) != -1) {
603                         ndr_print_string(ndr, idx, a[i]);
604                         free(idx);
605                 }
606         }
607         ndr->depth--;
608 }
609
610 _PUBLIC_ size_t ndr_size_string_array(const char **a, uint32_t count, int flags)
611 {
612         uint32_t i;
613         size_t size = 0;
614
615         switch (flags & LIBNDR_STRING_FLAGS) {
616         case LIBNDR_FLAG_STR_NULLTERM:
617                 for (i = 0; i < count; i++) {
618                         size += strlen_m_term(a[i]);
619                 }
620                 break;
621         case LIBNDR_FLAG_STR_NOTERM:
622                 for (i = 0; i < count; i++) {
623                         size += strlen_m(a[i]);
624                 }
625                 break;
626         default:
627                 return 0;
628         }
629
630         return size;
631 }
632
633 /**
634  * Return number of elements in a string including the last (zeroed) element 
635  */
636 _PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size)
637 {
638         uint32_t i;
639         uint8_t zero[4] = {0,0,0,0};
640         const char *var = (const char *)_var;
641
642         for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
643
644         return i+1;
645 }
646
647 _PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size)
648 {
649         uint32_t i;
650         uint32_t save_offset;
651
652         save_offset = ndr->offset;
653         ndr_pull_advance(ndr, (count - 1) * element_size);
654         NDR_PULL_NEED_BYTES(ndr, element_size);
655
656         for (i = 0; i < element_size; i++) {
657                  if (ndr->data[ndr->offset+i] != 0) {
658                         ndr->offset = save_offset;
659
660                         return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries");
661                  }
662         }
663
664         ndr->offset = save_offset;
665
666         return NDR_ERR_SUCCESS;
667 }
668
669 _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)
670 {
671         size_t converted_size;
672
673         if (length == 0) {
674                 *var = talloc_strdup(ndr->current_mem_ctx, "");
675                 return NDR_ERR_SUCCESS;
676         }
677
678         if (NDR_BE(ndr) && chset == CH_UTF16) {
679                 chset = CH_UTF16BE;
680         }
681
682         NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
683
684         if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
685                                    ndr->data+ndr->offset, length*byte_mul,
686                                    discard_const_p(void *, var),
687                                    &converted_size))
688         {
689                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
690                                       "Bad character conversion");
691         }
692         NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
693
694         return NDR_ERR_SUCCESS;
695 }
696
697 _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)
698 {
699         ssize_t ret, required;
700
701         if (NDR_BE(ndr) && chset == CH_UTF16) {
702                 chset = CH_UTF16BE;
703         }
704
705         required = byte_mul * length;
706         
707         NDR_PUSH_NEED_BYTES(ndr, required);
708         ret = convert_string(CH_UNIX, chset, 
709                              var, strlen(var),
710                              ndr->data+ndr->offset, required);
711         if (ret == -1) {
712                 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
713                                       "Bad character conversion");
714         }
715
716         /* Make sure the remaining part of the string is filled with zeroes */
717         if (ret < required) {
718                 memset(ndr->data+ndr->offset+ret, 0, required-ret);
719         }
720
721         ndr->offset += required;
722
723         return NDR_ERR_SUCCESS;
724 }
725
726 /* Return number of elements in a string in the specified charset */
727 _PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset)
728 {
729         switch (chset) {
730         /* case CH_UTF16: this has the same value as CH_UTF16LE */
731         case CH_UTF16LE:
732         case CH_UTF16BE:
733         case CH_UTF16MUNGED:
734         case CH_UTF8:
735                 return strlen_m_ext_term((const char *)var, CH_UNIX, chset);
736         case CH_DISPLAY:
737         case CH_DOS:
738         case CH_UNIX:
739                 return strlen((const char *)var)+1;
740         }
741
742         /* Fallback, this should never happen */
743         return strlen((const char *)var)+1;
744 }