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