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