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