Merge branch 'master' of ssh://git.samba.org/data/git/samba
[ira/wip.git] / source3 / 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, false))
90                         {
91                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
92                                                       "Bad character conversion");
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, false))
128                         {
129                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
130                                                       "Bad character conversion");
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, false))
167                         {
168                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
169                                                       "Bad character conversion");
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, false))
202                         {
203                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
204                                                       "Bad character conversion");
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, false))
234                         {
235                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
236                                                       "Bad character conversion");
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, false))
253                 {
254                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
255                                               "Bad character conversion");
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, false))
278                         {
279                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
280                                                       "Bad character conversion");
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, false))
338         {
339                 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
340                                       "Bad character conversion");
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 = *_a;
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                 /* 
458                  * here the strings are null terminated
459                  * but also the array is null terminated
460                  */
461                 for (count = 0;; count++) {
462                         TALLOC_CTX *tmp_ctx;
463                         const char *s = NULL;
464                         a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
465                         NDR_ERR_HAVE_NO_MEMORY(a);
466                         a[count]   = NULL;
467                         a[count+1]   = NULL;
468
469                         tmp_ctx = ndr->current_mem_ctx;
470                         ndr->current_mem_ctx = a;
471                         NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
472                         ndr->current_mem_ctx = tmp_ctx;
473                         if (strcmp("", s)==0) {
474                                 a[count] = NULL;
475                                 break;
476                         } else {
477                                 a[count] = s;
478                         }
479                 }
480
481                 *_a =a;
482                 break;
483
484         case LIBNDR_FLAG_STR_NOTERM:
485                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
486                         return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
487                                               ndr->flags & LIBNDR_STRING_FLAGS);
488                 }
489                 /*
490                  * here the strings are not null terminated
491                  * but serarated by a null terminator
492                  *
493                  * which means the same as:
494                  * very string is null terminated exept the last
495                  * string is terminated by the end of the buffer
496                  *
497                  * as LIBNDR_FLAG_STR_NULLTERM also end at the end
498                  * of the buffer, we can pull each string with this flag
499                  */
500                 ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
501                 ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
502
503                 for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) {
504                         TALLOC_CTX *tmp_ctx;
505                         const char *s = NULL;
506                         a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
507                         NDR_ERR_HAVE_NO_MEMORY(a);
508                         a[count]   = NULL;
509                         a[count+1]   = NULL;
510
511                         tmp_ctx = ndr->current_mem_ctx;
512                         ndr->current_mem_ctx = a;
513                         NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
514                         ndr->current_mem_ctx = tmp_ctx;
515                         a[count] = s;
516                 }
517
518                 *_a =a;
519                 break;
520
521         default:
522                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
523                                       ndr->flags & LIBNDR_STRING_FLAGS);
524         }
525
526         ndr->flags = saved_flags;
527         return NDR_ERR_SUCCESS;
528 }
529
530 /**
531   push a general string array onto the wire
532 */
533 _PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a)
534 {
535         uint32_t count;
536         unsigned flags = ndr->flags;
537         unsigned saved_flags = ndr->flags;
538
539         if (!(ndr_flags & NDR_SCALARS)) {
540                 return NDR_ERR_SUCCESS;
541         }
542
543         switch (flags & LIBNDR_STRING_FLAGS) {
544         case LIBNDR_FLAG_STR_NULLTERM:
545                 for (count = 0; a && a[count]; count++) {
546                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
547                 }
548
549                 NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
550                 break;
551
552         case LIBNDR_FLAG_STR_NOTERM:
553                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
554                         return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
555                                               ndr->flags & LIBNDR_STRING_FLAGS);
556                 }
557
558                 for (count = 0; a && a[count]; count++) {
559                         if (count > 0) {
560                                 ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
561                                 ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
562                                 NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
563                                 ndr->flags = saved_flags;
564                         }
565                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
566                 }
567
568                 break;
569
570         default:
571                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
572                                       ndr->flags & LIBNDR_STRING_FLAGS);
573         }
574         
575         ndr->flags = saved_flags;
576         return NDR_ERR_SUCCESS;
577 }
578
579 _PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
580 {
581         uint32_t count;
582         uint32_t i;
583
584         for (count = 0; a && a[count]; count++) {}
585
586         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
587         ndr->depth++;
588         for (i=0;i<count;i++) {
589                 char *idx=NULL;
590                 if (asprintf(&idx, "[%d]", i) != -1) {
591                         ndr_print_string(ndr, idx, a[i]);
592                         free(idx);
593                 }
594         }
595         ndr->depth--;
596 }
597
598 /**
599  * Return number of elements in a string including the last (zeroed) element 
600  */
601 _PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size)
602 {
603         uint32_t i;
604         uint8_t zero[4] = {0,0,0,0};
605         const char *var = (const char *)_var;
606
607         for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
608
609         return i+1;
610 }
611
612 _PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size)
613 {
614         uint32_t i;
615         uint32_t save_offset;
616
617         save_offset = ndr->offset;
618         ndr_pull_advance(ndr, (count - 1) * element_size);
619         NDR_PULL_NEED_BYTES(ndr, element_size);
620
621         for (i = 0; i < element_size; i++) {
622                  if (ndr->data[ndr->offset+i] != 0) {
623                         ndr->offset = save_offset;
624
625                         return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries");
626                  }
627         }
628
629         ndr->offset = save_offset;
630
631         return NDR_ERR_SUCCESS;
632 }
633
634 _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)
635 {
636         size_t converted_size;
637
638         if (length == 0) {
639                 *var = talloc_strdup(ndr->current_mem_ctx, "");
640                 return NDR_ERR_SUCCESS;
641         }
642
643         if (NDR_BE(ndr) && chset == CH_UTF16) {
644                 chset = CH_UTF16BE;
645         }
646
647         NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
648
649         if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
650                                    ndr->data+ndr->offset, length*byte_mul,
651                                    discard_const_p(void *, var),
652                                    &converted_size, false))
653         {
654                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
655                                       "Bad character conversion");
656         }
657         NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
658
659         return NDR_ERR_SUCCESS;
660 }
661
662 _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)
663 {
664         ssize_t ret, required;
665
666         if (NDR_BE(ndr) && chset == CH_UTF16) {
667                 chset = CH_UTF16BE;
668         }
669
670         required = byte_mul * length;
671         
672         NDR_PUSH_NEED_BYTES(ndr, required);
673         ret = convert_string(CH_UNIX, chset, 
674                              var, strlen(var),
675                              ndr->data+ndr->offset, required, false);
676         if (ret == -1) {
677                 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
678                                       "Bad character conversion");
679         }
680
681         /* Make sure the remaining part of the string is filled with zeroes */
682         if (ret < required) {
683                 memset(ndr->data+ndr->offset+ret, 0, required-ret);
684         }
685
686         ndr->offset += required;
687
688         return NDR_ERR_SUCCESS;
689 }
690
691 /* Return number of elements in a string in the specified charset */
692 _PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset)
693 {
694         /* FIXME: Treat special chars special here, taking chset into account */
695         /* Also include 0 byte */
696         return strlen((const char *)var)+1;
697 }