r9439: Make sure the remainder of the array is always initialized if the buffer is
[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 "system/network.h"
25
26 /*
27   pull a general string from the wire
28 */
29 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         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_LARGE_SIZE:
70                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
71                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
72                 if (ofs != 0) {
73                         return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
74                                               ndr->flags & LIBNDR_STRING_FLAGS);
75                 }
76                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
77                 if (len2 > len1) {
78                         return ndr_pull_error(ndr, NDR_ERR_STRING, 
79                                               "Bad string lengths len1=%u ofs=%u len2=%u\n", 
80                                               len1, ofs, len2);
81                 }
82                 if (len2 == 0) {
83                         *s = talloc_strdup(ndr, "");
84                         break;
85                 }
86                 NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul);
87                 ret = convert_string_talloc(ndr, chset, CH_UNIX, 
88                                             ndr->data+ndr->offset, 
89                                             (len2 + c_len_term)*byte_mul,
90                                             (void **)&as);
91                 if (ret == -1) {
92                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
93                                               "Bad character conversion");
94                 }
95                 NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul));
96
97                 if (ndr->flags & LIBNDR_FLAG_STR_LARGE_SIZE) {
98                         if (len1 != 0 && len2 == 0) {
99                                 DEBUG(6,("len1[%u] != (len2[%u]) '%s'\n", len1, len2, as));
100                         } else if (len1 != (len2 + 1)) {
101                                 DEBUG(6,("len1[%u] != (len2[%u]+1) '%s'\n", len1, len2, as));
102                         }
103                 } else {
104                         if (len1 != len2) {
105                                 DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as));
106                         }
107                 }
108
109                 /* this is a way of detecting if a string is sent with the wrong
110                    termination */
111                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
112                         if (strlen(as) < (len2 + c_len_term)) {
113                                 DEBUG(6,("short string '%s'\n", as));
114                         }
115                 } else {
116                         if (strlen(as) == (len2 + c_len_term)) {
117                                 DEBUG(6,("long string '%s'\n", as));
118                         }
119                 }
120                 *s = as;
121                 break;
122
123         case LIBNDR_FLAG_STR_SIZE4:
124         case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
125                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
126                 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
127                 if (len1 == 0) {
128                         *s = talloc_strdup(ndr, "");
129                         break;
130                 }
131                 ret = convert_string_talloc(ndr, chset, CH_UNIX, 
132                                             ndr->data+ndr->offset, 
133                                             (len1 + c_len_term)*byte_mul,
134                                             (void **)&as);
135                 if (ret == -1) {
136                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
137                                               "Bad character conversion");
138                 }
139                 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
140
141                 /* this is a way of detecting if a string is sent with the wrong
142                    termination */
143                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
144                         if (strlen(as) < (len1 + c_len_term)) {
145                                 DEBUG(6,("short string '%s'\n", as));
146                         }
147                 } else {
148                         if (strlen(as) == (len1 + c_len_term)) {
149                                 DEBUG(6,("long string '%s'\n", as));
150                         }
151                 }
152                 *s = as;
153                 break;
154
155         case LIBNDR_FLAG_STR_LEN4:
156         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
157                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
158                 if (ofs != 0) {
159                         return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
160                                               ndr->flags & LIBNDR_STRING_FLAGS);
161                 }
162                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
163                 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
164                 if (len1 == 0) {
165                         *s = talloc_strdup(ndr, "");
166                         break;
167                 }
168                 ret = convert_string_talloc(ndr, chset, CH_UNIX, 
169                                             ndr->data+ndr->offset, 
170                                             (len1 + c_len_term)*byte_mul,
171                                             (void **)&as);
172                 if (ret == -1) {
173                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
174                                               "Bad character conversion");
175                 }
176                 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
177
178                 /* this is a way of detecting if a string is sent with the wrong
179                    termination */
180                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
181                         if (strlen(as) < (len1 + c_len_term)) {
182                                 DEBUG(6,("short string '%s'\n", as));
183                         }
184                 } else {
185                         if (strlen(as) == (len1 + c_len_term)) {
186                                 DEBUG(6,("long string '%s'\n", as));
187                         }
188                 }
189                 *s = as;
190                 break;
191
192
193         case LIBNDR_FLAG_STR_SIZE2:
194         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
195                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
196                 NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul);
197                 if (len3 == 0) {
198                         *s = talloc_strdup(ndr, "");
199                         break;
200                 }
201                 ret = convert_string_talloc(ndr, chset, CH_UNIX, 
202                                             ndr->data+ndr->offset, 
203                                             (len3 + c_len_term)*byte_mul,
204                                             (void **)&as);
205                 if (ret == -1) {
206                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
207                                               "Bad character conversion");
208                 }
209                 NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul));
210
211                 /* this is a way of detecting if a string is sent with the wrong
212                    termination */
213                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
214                         if (strlen(as) < (len3 + c_len_term)) {
215                                 DEBUG(6,("short string '%s'\n", as));
216                         }
217                 } else {
218                         if (strlen(as) == (len3 + c_len_term)) {
219                                 DEBUG(6,("long string '%s'\n", as));
220                         }
221                 }
222                 *s = as;
223                 break;
224
225         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
226                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
227                 NDR_PULL_NEED_BYTES(ndr, len3);
228                 if (len3 == 0) {
229                         *s = talloc_strdup(ndr, "");
230                         break;
231                 }
232                 ret = convert_string_talloc(ndr, chset, CH_UNIX, 
233                                             ndr->data+ndr->offset, 
234                                             len3,
235                                             (void **)&as);
236                 if (ret == -1) {
237                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
238                                               "Bad character conversion");
239                 }
240                 NDR_CHECK(ndr_pull_advance(ndr, len3));
241                 *s = as;
242                 break;
243
244         case LIBNDR_FLAG_STR_NULLTERM:
245                 if (byte_mul == 1) {
246                         len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
247                 } else {
248                         len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
249                 }
250                 ret = convert_string_talloc(ndr, chset, CH_UNIX, 
251                                             ndr->data+ndr->offset, 
252                                             len1,
253                                             (void **)&as);
254                 if (ret == -1) {
255                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
256                                               "Bad character conversion");
257                 }
258                 NDR_CHECK(ndr_pull_advance(ndr, len1));
259                 *s = as;
260                 break;
261
262         case LIBNDR_FLAG_STR_FIXLEN15:
263         case LIBNDR_FLAG_STR_FIXLEN32:
264                 len1 = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15;
265                 NDR_PULL_NEED_BYTES(ndr, len1*byte_mul);
266                 ret = convert_string_talloc(ndr, chset, CH_UNIX, 
267                                             ndr->data+ndr->offset, 
268                                             len1*byte_mul,
269                                             (void **)&as);
270                 if (ret == -1) {
271                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
272                                               "Bad character conversion");
273                 }
274                 NDR_CHECK(ndr_pull_advance(ndr, len1*byte_mul));
275                 *s = as;
276                 break;
277
278         default:
279                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
280                                       ndr->flags & LIBNDR_STRING_FLAGS);
281         }
282
283         return NT_STATUS_OK;
284 }
285
286
287 /*
288   push a general string onto the wire
289 */
290 NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
291 {
292         ssize_t s_len, c_len, d_len;
293         int ret;
294         int chset = CH_UTF16;
295         unsigned flags = ndr->flags;
296         unsigned byte_mul = 2;
297         unsigned c_len_term = 1;
298
299         if (!(ndr_flags & NDR_SCALARS)) {
300                 return NT_STATUS_OK;
301         }
302
303         if (NDR_BE(ndr)) {
304                 chset = CH_UTF16BE;
305         }
306         
307         s_len = s?strlen(s):0;
308         c_len = s?strlen_m(s):0;
309
310         if (flags & LIBNDR_FLAG_STR_ASCII) {
311                 chset = CH_DOS;
312                 byte_mul = 1;
313                 flags &= ~LIBNDR_FLAG_STR_ASCII;
314         }
315
316         if (flags & LIBNDR_FLAG_STR_UTF8) {
317                 chset = CH_UTF8;
318                 byte_mul = 1;
319                 flags &= ~LIBNDR_FLAG_STR_UTF8;
320         }
321
322         flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
323
324         if (flags & LIBNDR_FLAG_STR_CHARLEN) {
325                 c_len_term = 0;
326                 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
327         }
328
329         switch (flags & LIBNDR_STRING_FLAGS) {
330         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
331                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len+c_len_term));
332                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
333                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len+c_len_term));
334                 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
335                 ret = convert_string(CH_UNIX, chset, 
336                                      s, s_len+1,
337                                      ndr->data+ndr->offset, 
338                                      byte_mul*(c_len+1));
339                 if (ret == -1) {
340                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
341                                               "Bad character conversion");
342                 }
343                 ndr->offset += byte_mul*(c_len+1);
344                 break;
345
346         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
347                 c_len_term = 0;
348         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_LARGE_SIZE:
349                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len+c_len_term));
350                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
351                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
352                 NDR_PUSH_NEED_BYTES(ndr, c_len*byte_mul);
353                 ret = convert_string(CH_UNIX, chset, 
354                                      s, s_len,
355                                      ndr->data+ndr->offset, c_len*byte_mul);
356                 if (ret == -1) {
357                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
358                                               "Bad character conversion");
359                 }
360                 ndr->offset += c_len*byte_mul;
361                 break;
362
363         case LIBNDR_FLAG_STR_LEN4:
364                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
365                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len + c_len_term));
366                 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
367                 ret = convert_string(CH_UNIX, chset, 
368                                      s, s_len + 1,
369                                      ndr->data+ndr->offset, byte_mul*(c_len+1));
370                 if (ret == -1) {
371                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
372                                               "Bad character conversion");
373                 }
374                 ndr->offset += byte_mul*(c_len+1);
375                 break;
376
377         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
378                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
379                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
380                 NDR_PUSH_NEED_BYTES(ndr, byte_mul*c_len);
381                 ret = convert_string(CH_UNIX, chset, 
382                                      s, s_len,
383                                      ndr->data+ndr->offset, byte_mul*c_len);
384                 if (ret == -1) {
385                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
386                                               "Bad character conversion");
387                 }
388                 ndr->offset += byte_mul*c_len;
389                 break;
390
391         case LIBNDR_FLAG_STR_SIZE4:
392                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len + c_len_term));
393                 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
394                 ret = convert_string(CH_UNIX, chset, 
395                                      s, s_len + 1,
396                                      ndr->data+ndr->offset, byte_mul*(c_len+1));
397                 if (ret == -1) {
398                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
399                                               "Bad character conversion");
400                 }
401                 ndr->offset += byte_mul*(c_len+1);
402                 break;
403
404         case LIBNDR_FLAG_STR_SIZE2:
405                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len + c_len_term));
406                 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
407                 ret = convert_string(CH_UNIX, chset, 
408                                      s, s_len + 1,
409                                      ndr->data+ndr->offset, byte_mul*(c_len+1));
410                 if (ret == -1) {
411                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
412                                               "Bad character conversion");
413                 }
414                 ndr->offset += byte_mul*(c_len+1);
415                 break;
416
417         case LIBNDR_FLAG_STR_NULLTERM:
418                 NDR_PUSH_NEED_BYTES(ndr, byte_mul*(c_len+1));
419                 ret = convert_string(CH_UNIX, chset, 
420                                      s, s_len+1,
421                                      ndr->data+ndr->offset, byte_mul*(c_len+1));
422                 if (ret == -1) {
423                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
424                                               "Bad character conversion");
425                 }
426                 ndr->offset += byte_mul*(c_len+1);
427                 break;
428
429         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
430                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len*byte_mul));
431                 NDR_PUSH_NEED_BYTES(ndr, c_len*byte_mul);
432                 ret = convert_string(CH_UNIX, chset, 
433                                      s, s_len,
434                                      ndr->data+ndr->offset, c_len*byte_mul);
435                 if (ret == -1) {
436                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
437                                               "Bad character conversion");
438                 }
439                 ndr->offset += c_len*byte_mul;
440                 break;
441
442         case LIBNDR_FLAG_STR_FIXLEN15:
443         case LIBNDR_FLAG_STR_FIXLEN32:
444                 d_len = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15;
445                 NDR_PUSH_NEED_BYTES(ndr, byte_mul*d_len);
446                 ret = convert_string(CH_UNIX, chset, 
447                                      s, s_len,
448                                      ndr->data+ndr->offset, byte_mul*d_len);
449                 if (ret == -1) {
450                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
451                                               "Bad character conversion");
452                 }
453                 ndr->offset += ret;
454                 if ((byte_mul*d_len) > ret) {
455                         uint32_t _padding_len = (byte_mul*d_len) - ret;
456                         NDR_CHECK(ndr_push_zero(ndr, _padding_len));
457                 }
458                 break;
459
460         default:
461                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
462                                       ndr->flags & LIBNDR_STRING_FLAGS);
463         }
464
465         return NT_STATUS_OK;
466 }
467
468 /*
469   push a general string onto the wire
470 */
471 size_t ndr_string_array_size(struct ndr_push *ndr, const char *s)
472 {
473         size_t c_len;
474         unsigned flags = ndr->flags;
475         unsigned byte_mul = 2;
476         unsigned c_len_term = 1;
477
478         if (flags & LIBNDR_FLAG_STR_FIXLEN32) {
479                 return 32;
480         }
481         if (flags & LIBNDR_FLAG_STR_FIXLEN15) {
482                 return 15;
483         }
484         
485         c_len = s?strlen_m(s):0;
486
487         if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_UTF8)) {
488                 byte_mul = 1;
489         }
490
491         if (flags & LIBNDR_FLAG_STR_NOTERM) {
492                 c_len_term = 0;
493         }
494
495         c_len = c_len + c_len_term;
496
497         if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
498                 c_len = c_len * byte_mul;
499         }
500
501         return c_len;
502 }
503
504 void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
505 {
506         if (s) {
507                 ndr->print(ndr, "%-25s: '%s'", name, s);
508         } else {
509                 ndr->print(ndr, "%-25s: NULL", name);
510         }
511 }
512
513 uint32_t ndr_size_string(int ret, const char * const* string, int flags) 
514 {
515         /* FIXME: Is this correct for all strings ? */
516         if(!(*string)) return ret;
517         return ret+strlen(*string)+1;
518 }
519
520 /*
521   pull a general string array from the wire
522 */
523 NTSTATUS ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a)
524 {
525         const char **a = *_a;
526         uint32_t count;
527
528         if (!(ndr_flags & NDR_SCALARS)) {
529                 return NT_STATUS_OK;
530         }
531
532         for (count = 0;; count++) {
533                 const char *s = NULL;
534                 a = talloc_realloc(ndr, a, const char *, count + 2);
535                 NT_STATUS_HAVE_NO_MEMORY(a);
536                 a[count]   = NULL;
537                 a[count+1]   = NULL;
538
539                 NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
540                 if (strcmp("", s)==0) {
541                         a[count] = NULL;
542                         break;
543                 } else {
544                         a[count] = s;
545                 }
546         }
547
548         *_a =a;
549         return NT_STATUS_OK;
550 }
551
552 /*
553   push a general string array onto the wire
554 */
555 NTSTATUS ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a)
556 {
557         uint32_t count;
558
559         if (!(ndr_flags & NDR_SCALARS)) {
560                 return NT_STATUS_OK;
561         }
562
563         for (count = 0; a && a[count]; count++) {
564                 NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
565         }
566
567         NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
568
569         return NT_STATUS_OK;
570 }
571
572 void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
573 {
574         uint32_t count;
575         uint32_t i;
576
577         for (count = 0; a && a[count]; count++) {}
578
579         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
580         ndr->depth++;
581         for (i=0;i<count;i++) {
582                 char *idx=NULL;
583                 asprintf(&idx, "[%d]", i);
584                 if (idx) {
585                         ndr_print_string(ndr, idx, a[i]);
586                         free(idx);
587                 }
588         }
589         ndr->depth--;
590 }
591
592 /* Return number of elements in a string including the last (zeroed) element */
593 uint32_t ndr_string_length(const void *_var, uint32_t element_size)
594 {
595         uint32_t i;
596         uint8_t zero[4] = {0,0,0,0};
597         const char *var = _var;
598
599         for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
600
601         return i+1;
602 }
603
604 NTSTATUS ndr_check_string_terminator(struct ndr_pull *ndr, const void *_var, uint32_t count, uint32_t element_size)
605 {
606         const char *var = _var;
607         uint32_t i;
608
609         var += element_size*(count-1);
610
611         for (i = 0; i < element_size; i++) {
612                  if (var[i] != 0) {
613                         return NT_STATUS_UNSUCCESSFUL;
614                  }
615         }
616
617         return NT_STATUS_OK;
618
619 }
620
621 NTSTATUS ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, int chset)
622 {
623         int ret;
624         if (length == 0) {
625                 *var = talloc_strdup(ndr, "");
626                 return NT_STATUS_OK;
627         }
628         NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
629         ret = convert_string_talloc(ndr, chset, CH_UNIX, 
630                                     ndr->data+ndr->offset, 
631                                     length*byte_mul,
632                                     discard_const_p(void *, var));
633         if (ret == -1) {
634                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
635                                       "Bad character conversion");
636         }
637         NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
638
639         return NT_STATUS_OK;
640 }
641
642 NTSTATUS ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, int chset)
643 {
644         ssize_t ret;
645         NDR_PUSH_NEED_BYTES(ndr, byte_mul*length);
646         ret = convert_string(CH_UNIX, chset, 
647                              var, length,
648                              ndr->data+ndr->offset, byte_mul*length);
649         if (ret == -1) {
650                 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
651                                       "Bad character conversion");
652         }
653
654         /* Make sure the remaining part of the string is filled with zeroes */
655         if (ret < (byte_mul*length)) {
656                 memset(ndr->data+ndr->offset+ret, 0, (byte_mul*length)-ret);
657         }
658
659         ndr->offset += length;
660
661         return NT_STATUS_OK;
662 }