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