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