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