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