1 /*
2    Unix SMB/CIFS implementation.
3 
4    libndr interface
5 
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Jelmer Vernooij 2005-2008
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 /*
24   this provides the core routines for NDR parsing functions
25 
26   see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
27   of NDR encoding rules
28 */
29 
30 #include "includes.h"
31 #include "librpc/ndr/libndr.h"
32 #include "../lib/util/dlinklist.h"
33 
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_RPC_PARSE
36 
37 #define NDR_BASE_MARSHALL_SIZE 1024
38 
39 /*
40  * This value is arbitary, but designed to reduce the memory a client
41  * can allocate and the work the client can force in processing a
42  * malicious packet.
43  *
44  * In an ideal world this would be controlled by range() restrictions
45  * on array sizes and careful IDL construction to avoid arbitary
46  * linked lists, but this is a backstop for now.
47  */
48 #define NDR_TOKEN_MAX_LIST_SIZE 65535
49 
50 /* this guid indicates NDR encoding in a protocol tower */
51 const struct ndr_syntax_id ndr_transfer_syntax_ndr = {
52   { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
53   2
54 };
55 
56 const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
57   { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
58   1
59 };
60 
61 const struct ndr_syntax_id ndr_syntax_id_null = {
62   { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
63   0
64 };
65 
66 /*
67   work out the number of bytes needed to align on a n byte boundary
68 */
ndr_align_size(uint32_t offset,size_t n)69 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
70 {
71 	if ((offset & (n-1)) == 0) return 0;
72 	return n - (offset & (n-1));
73 }
74 
75 /*
76   initialise a ndr parse structure from a data blob
77 */
ndr_pull_init_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx)78 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
79 {
80 	struct ndr_pull *ndr;
81 
82 	ndr = talloc_zero(mem_ctx, struct ndr_pull);
83 	if (!ndr) return NULL;
84 	ndr->current_mem_ctx = mem_ctx;
85 
86 	ndr->data = blob->data;
87 	ndr->data_size = blob->length;
88 
89 	return ndr;
90 }
91 
ndr_pull_append(struct ndr_pull * ndr,DATA_BLOB * blob)92 _PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
93 {
94 	enum ndr_err_code ndr_err;
95 	DATA_BLOB b;
96 	uint32_t append = 0;
97 	bool ok;
98 
99 	if (blob->length == 0) {
100 		return NDR_ERR_SUCCESS;
101 	}
102 
103 	ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
104 	if (ndr_err == NDR_ERR_TOKEN) {
105 		append = 0;
106 		ndr_err = NDR_ERR_SUCCESS;
107 	}
108 	NDR_CHECK(ndr_err);
109 
110 	if (ndr->data_size == 0) {
111 		ndr->data = NULL;
112 		append = UINT32_MAX;
113 	}
114 
115 	if (append == UINT32_MAX) {
116 		/*
117 		 * append == UINT32_MAX means that
118 		 * ndr->data is either NULL or a valid
119 		 * talloc child of ndr, which means
120 		 * we can use data_blob_append() without
121 		 * data_blob_talloc() of the existing callers data
122 		 */
123 		b = data_blob_const(ndr->data, ndr->data_size);
124 	} else {
125 		b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
126 		if (b.data == NULL) {
127 			return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
128 		}
129 	}
130 
131 	ok = data_blob_append(ndr, &b, blob->data, blob->length);
132 	if (!ok) {
133 		return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
134 	}
135 
136 	ndr->data = b.data;
137 	ndr->data_size = b.length;
138 
139 	return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
140 }
141 
ndr_pull_pop(struct ndr_pull * ndr)142 _PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
143 {
144 	uint32_t skip = 0;
145 	uint32_t append = 0;
146 
147 	if (ndr->relative_base_offset != 0) {
148 		return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
149 				      "%s", __location__);
150 	}
151 	if (ndr->relative_highest_offset != 0) {
152 		return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
153 				      "%s", __location__);
154 	}
155 	if (ndr->relative_list.count != 0) {
156 		return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
157 				      "%s", __location__);
158 	}
159 	if (ndr->relative_base_list.count != 0) {
160 		return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
161 				      "%s", __location__);
162 	}
163 
164 	/*
165 	 * we need to keep up to 7 bytes
166 	 * in order to get the aligment right.
167 	 */
168 	skip = ndr->offset & 0xFFFFFFF8;
169 
170 	if (skip == 0) {
171 		return NDR_ERR_SUCCESS;
172 	}
173 
174 	ndr->offset -= skip;
175 	ndr->data_size -= skip;
176 
177 	append = ndr_token_peek(&ndr->array_size_list, ndr);
178 	if (append != UINT32_MAX) {
179 		/*
180 		 * here we assume, that ndr->data is not a
181 		 * talloc child of ndr.
182 		 */
183 		ndr->data += skip;
184 		return NDR_ERR_SUCCESS;
185 	}
186 
187 	memmove(ndr->data, ndr->data + skip, ndr->data_size);
188 
189 	ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
190 	if (ndr->data_size != 0 && ndr->data == NULL) {
191 		return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
192 	}
193 
194 	return NDR_ERR_SUCCESS;
195 }
196 
197 /*
198   advance by 'size' bytes
199 */
ndr_pull_advance(struct ndr_pull * ndr,uint32_t size)200 _PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
201 {
202 	ndr->offset += size;
203 	if (ndr->offset > ndr->data_size) {
204 		return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
205 				      "ndr_pull_advance by %u failed",
206 				      size);
207 	}
208 	return NDR_ERR_SUCCESS;
209 }
210 
211 /*
212   set the parse offset to 'ofs'
213 */
ndr_pull_set_offset(struct ndr_pull * ndr,uint32_t ofs)214 static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
215 {
216 	ndr->offset = ofs;
217 	if (ndr->offset > ndr->data_size) {
218 		return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
219 				      "ndr_pull_set_offset %u failed",
220 				      ofs);
221 	}
222 	return NDR_ERR_SUCCESS;
223 }
224 
225 /* create a ndr_push structure, ready for some marshalling */
ndr_push_init_ctx(TALLOC_CTX * mem_ctx)226 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
227 {
228 	struct ndr_push *ndr;
229 
230 	ndr = talloc_zero(mem_ctx, struct ndr_push);
231 	if (!ndr) {
232 		return NULL;
233 	}
234 
235 	ndr->flags = 0;
236 	ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
237 	ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
238 	if (!ndr->data) {
239 		talloc_free(ndr);
240 		return NULL;
241 	}
242 
243 	return ndr;
244 }
245 
246 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
ndr_push_blob(struct ndr_push * ndr)247 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
248 {
249 	DATA_BLOB blob;
250 	blob = data_blob_const(ndr->data, ndr->offset);
251 	if (ndr->alloc_size > ndr->offset) {
252 		ndr->data[ndr->offset] = 0;
253 	}
254 	return blob;
255 }
256 
257 
258 /*
259   expand the available space in the buffer to ndr->offset + extra_size
260 */
ndr_push_expand(struct ndr_push * ndr,uint32_t extra_size)261 _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
262 {
263 	uint32_t size = extra_size + ndr->offset;
264 
265 	if (size < ndr->offset) {
266 		/* extra_size overflowed the offset */
267 		return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
268 				      size);
269 	}
270 
271 	if (ndr->fixed_buf_size) {
272 		if (ndr->alloc_size >= size) {
273 			return NDR_ERR_SUCCESS;
274 		}
275 		return ndr_push_error(ndr,
276 				      NDR_ERR_BUFSIZE,
277 				      "Overflow of fixed buffer in "
278 				      "push_expand to %u",
279 				      size);
280 	}
281 
282 	if (ndr->alloc_size > size) {
283 		return NDR_ERR_SUCCESS;
284 	}
285 
286 	ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
287 	if (size+1 > ndr->alloc_size) {
288 		ndr->alloc_size = size+1;
289 	}
290 	ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
291 	if (!ndr->data) {
292 		return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
293 				      ndr->alloc_size);
294 	}
295 
296 	return NDR_ERR_SUCCESS;
297 }
298 
ndr_print_debugc_helper(struct ndr_print * ndr,const char * format,...)299 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
300 {
301 	va_list ap;
302 	char *s = NULL;
303 	uint32_t i;
304 	int ret;
305 	int dbgc_class;
306 
307 	va_start(ap, format);
308 	ret = vasprintf(&s, format, ap);
309 	va_end(ap);
310 
311 	if (ret == -1) {
312 		return;
313 	}
314 
315 	dbgc_class = *(int *)ndr->private_data;
316 
317 	if (ndr->no_newline) {
318 		DEBUGADDC(dbgc_class, 1,("%s", s));
319 		free(s);
320 		return;
321 	}
322 
323 	for (i=0;i<ndr->depth;i++) {
324 		DEBUGADDC(dbgc_class, 1,("    "));
325 	}
326 
327 	DEBUGADDC(dbgc_class, 1,("%s\n", s));
328 	free(s);
329 }
330 
ndr_print_debug_helper(struct ndr_print * ndr,const char * format,...)331 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
332 {
333 	va_list ap;
334 	char *s = NULL;
335 	uint32_t i;
336 	int ret;
337 
338 	va_start(ap, format);
339 	ret = vasprintf(&s, format, ap);
340 	va_end(ap);
341 
342 	if (ret == -1) {
343 		return;
344 	}
345 
346 	if (ndr->no_newline) {
347 		DEBUGADD(1,("%s", s));
348 		free(s);
349 		return;
350 	}
351 
352 	for (i=0;i<ndr->depth;i++) {
353 		DEBUGADD(1,("    "));
354 	}
355 
356 	DEBUGADD(1,("%s\n", s));
357 	free(s);
358 }
359 
ndr_print_printf_helper(struct ndr_print * ndr,const char * format,...)360 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
361 {
362 	va_list ap;
363 	uint32_t i;
364 
365 	if (!ndr->no_newline) {
366 		for (i=0;i<ndr->depth;i++) {
367 			printf("    ");
368 		}
369 	}
370 
371 	va_start(ap, format);
372 	vprintf(format, ap);
373 	va_end(ap);
374 	if (!ndr->no_newline) {
375 		printf("\n");
376 	}
377 }
378 
ndr_print_string_helper(struct ndr_print * ndr,const char * format,...)379 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
380 {
381 	va_list ap;
382 	uint32_t i;
383 
384 	if (!ndr->no_newline) {
385 		for (i=0;i<ndr->depth;i++) {
386 			ndr->private_data = talloc_asprintf_append_buffer(
387 				(char *)ndr->private_data, "    ");
388 		}
389 	}
390 
391 	va_start(ap, format);
392 	ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
393 						    format, ap);
394 	va_end(ap);
395 	if (!ndr->no_newline) {
396 		ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
397 								  "\n");
398 	}
399 }
400 
401 /*
402   a useful helper function for printing idl structures via DEBUGC()
403 */
ndr_print_debugc(int dbgc_class,ndr_print_fn_t fn,const char * name,void * ptr)404 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
405 {
406 	struct ndr_print *ndr;
407 
408 	DEBUGC(dbgc_class, 1,(" "));
409 
410 	ndr = talloc_zero(NULL, struct ndr_print);
411 	if (!ndr) return;
412 	ndr->private_data = &dbgc_class;
413 	ndr->print = ndr_print_debugc_helper;
414 	ndr->depth = 1;
415 	ndr->flags = 0;
416 #ifdef DEBUG_PASSWORD
417 	if (CHECK_DEBUGLVL(100)) {
418 		ndr->print_secrets = true;
419 	}
420 #endif
421 
422 	fn(ndr, name, ptr);
423 	talloc_free(ndr);
424 }
425 
426 /*
427   a useful helper function for printing idl structures via DEBUG()
428 */
ndr_print_debug(ndr_print_fn_t fn,const char * name,void * ptr)429 _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
430 {
431 	struct ndr_print *ndr;
432 
433 	DEBUG(1,(" "));
434 
435 	ndr = talloc_zero(NULL, struct ndr_print);
436 	if (!ndr) return;
437 	ndr->print = ndr_print_debug_helper;
438 	ndr->depth = 1;
439 	ndr->flags = 0;
440 #ifdef DEBUG_PASSWORD
441 	if (CHECK_DEBUGLVL(100)) {
442 		ndr->print_secrets = true;
443 	}
444 #endif
445 
446 	fn(ndr, name, ptr);
447 	talloc_free(ndr);
448 }
449 
450 /*
451   a useful helper function for printing idl unions via DEBUG()
452 */
ndr_print_union_debug(ndr_print_fn_t fn,const char * name,uint32_t level,void * ptr)453 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
454 {
455 	struct ndr_print *ndr;
456 
457 	DEBUG(1,(" "));
458 
459 	ndr = talloc_zero(NULL, struct ndr_print);
460 	if (!ndr) return;
461 	ndr->print = ndr_print_debug_helper;
462 	ndr->depth = 1;
463 	ndr->flags = 0;
464 #ifdef DEBUG_PASSWORD
465 	if (CHECK_DEBUGLVL(100)) {
466 		ndr->print_secrets = true;
467 	}
468 #endif
469 
470 	ndr_print_set_switch_value(ndr, ptr, level);
471 	fn(ndr, name, ptr);
472 	talloc_free(ndr);
473 }
474 
475 /*
476   a useful helper function for printing idl function calls via DEBUG()
477 */
ndr_print_function_debug(ndr_print_function_t fn,const char * name,int flags,void * ptr)478 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
479 {
480 	struct ndr_print *ndr;
481 
482 	DEBUG(1,(" "));
483 
484 	ndr = talloc_zero(NULL, struct ndr_print);
485 	if (!ndr) return;
486 	ndr->print = ndr_print_debug_helper;
487 	ndr->depth = 1;
488 	ndr->flags = 0;
489 #ifdef DEBUG_PASSWORD
490 	if (CHECK_DEBUGLVL(100)) {
491 		ndr->print_secrets = true;
492 	}
493 #endif
494 
495 	fn(ndr, name, flags, ptr);
496 	talloc_free(ndr);
497 }
498 
499 /*
500   a useful helper function for printing idl structures to a string
501 */
ndr_print_struct_string(TALLOC_CTX * mem_ctx,ndr_print_fn_t fn,const char * name,void * ptr)502 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
503 {
504 	struct ndr_print *ndr;
505 	char *ret = NULL;
506 
507 	ndr = talloc_zero(mem_ctx, struct ndr_print);
508 	if (!ndr) return NULL;
509 	ndr->private_data = talloc_strdup(ndr, "");
510 	if (!ndr->private_data) {
511 		goto failed;
512 	}
513 	ndr->print = ndr_print_string_helper;
514 	ndr->depth = 1;
515 	ndr->flags = 0;
516 
517 	fn(ndr, name, ptr);
518 	ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
519 failed:
520 	talloc_free(ndr);
521 	return ret;
522 }
523 
524 /*
525   a useful helper function for printing idl unions to a string
526 */
ndr_print_union_string(TALLOC_CTX * mem_ctx,ndr_print_fn_t fn,const char * name,uint32_t level,void * ptr)527 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
528 {
529 	struct ndr_print *ndr;
530 	char *ret = NULL;
531 
532 	ndr = talloc_zero(mem_ctx, struct ndr_print);
533 	if (!ndr) return NULL;
534 	ndr->private_data = talloc_strdup(ndr, "");
535 	if (!ndr->private_data) {
536 		goto failed;
537 	}
538 	ndr->print = ndr_print_string_helper;
539 	ndr->depth = 1;
540 	ndr->flags = 0;
541 	ndr_print_set_switch_value(ndr, ptr, level);
542 	fn(ndr, name, ptr);
543 	ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
544 failed:
545 	talloc_free(ndr);
546 	return ret;
547 }
548 
549 /*
550   a useful helper function for printing idl function calls to a string
551 */
ndr_print_function_string(TALLOC_CTX * mem_ctx,ndr_print_function_t fn,const char * name,int flags,void * ptr)552 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
553 				ndr_print_function_t fn, const char *name,
554 				int flags, void *ptr)
555 {
556 	struct ndr_print *ndr;
557 	char *ret = NULL;
558 
559 	ndr = talloc_zero(mem_ctx, struct ndr_print);
560 	if (!ndr) return NULL;
561 	ndr->private_data = talloc_strdup(ndr, "");
562 	if (!ndr->private_data) {
563 		goto failed;
564 	}
565 	ndr->print = ndr_print_string_helper;
566 	ndr->depth = 1;
567 	ndr->flags = 0;
568 	fn(ndr, name, flags, ptr);
569 	ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
570 failed:
571 	talloc_free(ndr);
572 	return ret;
573 }
574 
ndr_set_flags(uint32_t * pflags,uint32_t new_flags)575 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
576 {
577 	/* the big/little endian flags are inter-dependent */
578 	if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
579 		(*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
580 		(*pflags) &= ~LIBNDR_FLAG_NDR64;
581 	}
582 	if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
583 		(*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
584 		(*pflags) &= ~LIBNDR_FLAG_NDR64;
585 	}
586 	if (new_flags & LIBNDR_ALIGN_FLAGS) {
587 		/* Ensure we only have the passed-in
588 		   align flag set in the new_flags,
589 		   remove any old align flag. */
590 		(*pflags) &= ~LIBNDR_ALIGN_FLAGS;
591 	}
592 	if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
593 		(*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
594 	}
595 	(*pflags) |= new_flags;
596 }
597 
598 /*
599   return and possibly log an NDR error
600 */
_ndr_pull_error(struct ndr_pull * ndr,enum ndr_err_code ndr_err,const char * function,const char * location,const char * format,...)601 _PUBLIC_ enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr,
602 					   enum ndr_err_code ndr_err,
603 					   const char *function,
604 					   const char *location,
605 					   const char *format, ...)
606 {
607 	char *s=NULL;
608 	va_list ap;
609 	int ret;
610 
611 	if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
612 		switch (ndr_err) {
613 		case NDR_ERR_BUFSIZE:
614 			return NDR_ERR_INCOMPLETE_BUFFER;
615 		default:
616 			break;
617 		}
618 	}
619 
620 	va_start(ap, format);
621 	ret = vasprintf(&s, format, ap);
622 	va_end(ap);
623 
624 	if (ret == -1) {
625 		return NDR_ERR_ALLOC;
626 	}
627 
628 	D_WARNING("%s: ndr_pull_error(%s): %s at %s\n",
629 		  function,
630 		  ndr_map_error2string(ndr_err),
631 		  s,
632 		  location);
633 
634 	free(s);
635 
636 	return ndr_err;
637 }
638 
639 /*
640   return and possibly log an NDR error
641 */
_ndr_push_error(struct ndr_push * ndr,enum ndr_err_code ndr_err,const char * function,const char * location,const char * format,...)642 _PUBLIC_ enum ndr_err_code _ndr_push_error(struct ndr_push *ndr,
643 					   enum ndr_err_code ndr_err,
644 					   const char *function,
645 					   const char *location,
646 					   const char *format, ...)
647 {
648 	char *s=NULL;
649 	va_list ap;
650 	int ret;
651 
652 	va_start(ap, format);
653 	ret = vasprintf(&s, format, ap);
654 	va_end(ap);
655 
656 	if (ret == -1) {
657 		return NDR_ERR_ALLOC;
658 	}
659 
660 	D_WARNING("%s: ndr_push_error(%s): %s at %s\n",
661 		  function,
662 		  ndr_map_error2string(ndr_err),
663 		  s,
664 		  location);
665 
666 	free(s);
667 
668 	return ndr_err;
669 }
670 
671 /*
672   handle subcontext buffers, which in midl land are user-marshalled, but
673   we use magic in pidl to make them easier to cope with
674 */
ndr_pull_subcontext_start(struct ndr_pull * ndr,struct ndr_pull ** _subndr,size_t header_size,ssize_t size_is)675 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
676 				   struct ndr_pull **_subndr,
677 				   size_t header_size,
678 				   ssize_t size_is)
679 {
680 	struct ndr_pull *subndr;
681 	uint32_t r_content_size;
682 	bool force_le = false;
683 	bool force_be = false;
684 
685 	switch (header_size) {
686 	case 0: {
687 		uint32_t content_size = ndr->data_size - ndr->offset;
688 		if (size_is >= 0) {
689 			content_size = size_is;
690 		}
691 		r_content_size = content_size;
692 		break;
693 	}
694 
695 	case 2: {
696 		uint16_t content_size;
697 		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
698 		if (size_is >= 0 && size_is != content_size) {
699 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%04x) mismatch content_size %d (0x%04x)",
700 						(int)size_is, (int)size_is,
701 						(int)content_size,
702 						(int)content_size);
703 		}
704 		r_content_size = content_size;
705 		break;
706 	}
707 
708 	case 4: {
709 		uint32_t content_size;
710 		NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
711 		if (size_is >= 0 && size_is != content_size) {
712 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%08x) mismatch content_size %d (0x%08x)",
713 						(int)size_is, (int)size_is,
714 						(int)content_size,
715 						(int)content_size);
716 		}
717 		r_content_size = content_size;
718 		break;
719 	}
720 	case 0xFFFFFC01: {
721 		/*
722 		 * Common Type Header for the Serialization Stream
723 		 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
724 		 */
725 		uint8_t version;
726 		uint8_t drep;
727 		uint16_t hdrlen;
728 		uint32_t filler;
729 		uint32_t content_size;
730 		uint32_t reserved;
731 
732 		/* version */
733 		NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
734 
735 		if (version != 1) {
736 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
737 					      "Bad subcontext (PULL) Common Type Header version %d != 1",
738 					      (int)version);
739 		}
740 
741 		/*
742 		 * 0x10 little endian
743 		 * 0x00 big endian
744 		 */
745 		NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
746 		if (drep == 0x10) {
747 			force_le = true;
748 		} else if (drep == 0x00) {
749 			force_be = true;
750 		} else {
751 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
752 					      "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
753 					      (unsigned int)drep);
754 		}
755 
756 		/* length of the "Private Header for Constructed Type" */
757 		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
758 		if (hdrlen != 8) {
759 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
760 					      "Bad subcontext (PULL) Common Type Header length %d != 8",
761 					      (int)hdrlen);
762 		}
763 
764 		/* filler should be ignored */
765 		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
766 
767 		/*
768 		 * Private Header for Constructed Type
769 		 */
770 		/* length - will be updated latter */
771 		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
772 		if (size_is >= 0 && size_is != content_size) {
773 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
774 					      (int)size_is, (int)content_size);
775 		}
776 		/* the content size must be a multiple of 8 */
777 		if ((content_size % 8) != 0) {
778 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
779 					      "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
780 					      (int)size_is, (int)content_size);
781 		}
782 		r_content_size = content_size;
783 
784 		/* reserved */
785 		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
786 		break;
787 	}
788 	case 0xFFFFFFFF:
789 		/*
790 		 * a shallow copy like subcontext
791 		 * useful for DCERPC pipe chunks.
792 		 */
793 		subndr = talloc_zero(ndr, struct ndr_pull);
794 		NDR_ERR_HAVE_NO_MEMORY(subndr);
795 
796 		subndr->flags		= ndr->flags;
797 		subndr->current_mem_ctx	= ndr->current_mem_ctx;
798 		subndr->data		= ndr->data;
799 		subndr->offset		= ndr->offset;
800 		subndr->data_size	= ndr->data_size;
801 
802 		*_subndr = subndr;
803 		return NDR_ERR_SUCCESS;
804 
805 	default:
806 		return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
807 				      (int)header_size);
808 	}
809 
810 	NDR_PULL_NEED_BYTES(ndr, r_content_size);
811 
812 	subndr = talloc_zero(ndr, struct ndr_pull);
813 	NDR_ERR_HAVE_NO_MEMORY(subndr);
814 	subndr->flags		= ndr->flags & ~LIBNDR_FLAG_NDR64;
815 	subndr->current_mem_ctx	= ndr->current_mem_ctx;
816 
817 	subndr->data = ndr->data + ndr->offset;
818 	subndr->offset = 0;
819 	subndr->data_size = r_content_size;
820 
821 	if (force_le) {
822 		ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
823 	} else if (force_be) {
824 		ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
825 	}
826 
827 	*_subndr = subndr;
828 	return NDR_ERR_SUCCESS;
829 }
830 
ndr_pull_subcontext_end(struct ndr_pull * ndr,struct ndr_pull * subndr,size_t header_size,ssize_t size_is)831 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
832 				 struct ndr_pull *subndr,
833 				 size_t header_size,
834 				 ssize_t size_is)
835 {
836 	uint32_t advance;
837 	uint32_t highest_ofs;
838 
839 	if (header_size == 0xFFFFFFFF) {
840 		advance = subndr->offset - ndr->offset;
841 	} else if (size_is >= 0) {
842 		advance = size_is;
843 	} else if (header_size > 0) {
844 		advance = subndr->data_size;
845 	} else {
846 		advance = subndr->offset;
847 	}
848 
849 	if (subndr->offset > ndr->relative_highest_offset) {
850 		highest_ofs = subndr->offset;
851 	} else {
852 		highest_ofs = subndr->relative_highest_offset;
853 	}
854 	if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
855 		/*
856 		 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
857 		 */
858 		highest_ofs = advance;
859 	}
860 	if (highest_ofs < advance) {
861 		return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
862 				      "not all bytes consumed ofs[%u] advance[%u]",
863 				      highest_ofs, advance);
864 	}
865 
866 	NDR_CHECK(ndr_pull_advance(ndr, advance));
867 	return NDR_ERR_SUCCESS;
868 }
869 
ndr_push_subcontext_start(struct ndr_push * ndr,struct ndr_push ** _subndr,size_t header_size,ssize_t size_is)870 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
871 				   struct ndr_push **_subndr,
872 				   size_t header_size,
873 				   ssize_t size_is)
874 {
875 	struct ndr_push *subndr;
876 
877 	subndr = ndr_push_init_ctx(ndr);
878 	NDR_ERR_HAVE_NO_MEMORY(subndr);
879 	subndr->flags	= ndr->flags & ~LIBNDR_FLAG_NDR64;
880 
881 	if (size_is > 0) {
882 		NDR_CHECK(ndr_push_zero(subndr, size_is));
883 		subndr->offset = 0;
884 		subndr->relative_end_offset = size_is;
885 	}
886 
887 	*_subndr = subndr;
888 	return NDR_ERR_SUCCESS;
889 }
890 
891 /*
892   push a subcontext header
893 */
ndr_push_subcontext_end(struct ndr_push * ndr,struct ndr_push * subndr,size_t header_size,ssize_t size_is)894 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
895 				 struct ndr_push *subndr,
896 				 size_t header_size,
897 				 ssize_t size_is)
898 {
899 	ssize_t padding_len;
900 
901 	if (size_is >= 0) {
902 		padding_len = size_is - subndr->offset;
903 		if (padding_len < 0) {
904 			return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
905 					      (int)subndr->offset, (int)size_is);
906 		}
907 		subndr->offset = size_is;
908 	}
909 
910 	switch (header_size) {
911 	case 0:
912 		break;
913 
914 	case 2:
915 		NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
916 		break;
917 
918 	case 4:
919 		NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
920 		break;
921 
922 	case 0xFFFFFC01:
923 		/*
924 		 * Common Type Header for the Serialization Stream
925 		 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
926 		 */
927 		padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
928 		if (padding_len > 0) {
929 			NDR_CHECK(ndr_push_zero(subndr, padding_len));
930 		}
931 
932 		/* version */
933 		NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
934 
935 		/*
936 		 * 0x10 little endian
937 		 * 0x00 big endian
938 		 */
939 		NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
940 
941 		/* length of the "Private Header for Constructed Type" */
942 		NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
943 
944 		/* filler */
945 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
946 
947 		/*
948 		 * Private Header for Constructed Type
949 		 */
950 		/* length - will be updated latter */
951 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
952 
953 		/* reserved */
954 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
955 		break;
956 
957 	default:
958 		return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
959 				      (int)header_size);
960 	}
961 
962 	NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
963 	return NDR_ERR_SUCCESS;
964 }
965 
966 
967 struct ndr_token {
968 	const void *key;
969 	uint32_t value;
970 };
971 
972 /*
973   store a token in the ndr context, for later retrieval
974 */
ndr_token_store(TALLOC_CTX * mem_ctx,struct ndr_token_list * list,const void * key,uint32_t value)975 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
976 			 struct ndr_token_list *list,
977 			 const void *key,
978 			 uint32_t value)
979 {
980 	if (list->tokens == NULL) {
981 		list->tokens = talloc_array(mem_ctx, struct ndr_token, 10);
982 		if (list->tokens == NULL) {
983 			NDR_ERR_HAVE_NO_MEMORY(list->tokens);
984 		}
985 	} else {
986 		struct ndr_token *new_tokens = NULL;
987 		uint32_t alloc_count = talloc_array_length(list->tokens);
988 
989 		/*
990 		 * Check every time we have not allocated too many
991 		 * tokens.  This ensures developer sanity when
992 		 * debugging the boundary condition
993 		 */
994 		if (list->count >= NDR_TOKEN_MAX_LIST_SIZE) {
995 			return NDR_ERR_RANGE;
996 		}
997 		if (list->count == alloc_count) {
998 			unsigned new_alloc;
999 			/*
1000 			 * Double the list, until we start in chunks
1001 			 * of 1000
1002 			 */
1003 			unsigned increment = MIN(list->count, 1000);
1004 			new_alloc = alloc_count + increment;
1005 			if (new_alloc < alloc_count) {
1006 				return NDR_ERR_RANGE;
1007 			}
1008 			new_tokens = talloc_realloc(mem_ctx, list->tokens,
1009 						    struct ndr_token, new_alloc);
1010 			NDR_ERR_HAVE_NO_MEMORY(new_tokens);
1011 			list->tokens = new_tokens;
1012 		}
1013 	}
1014 	list->tokens[list->count].key = key;
1015 	list->tokens[list->count].value = value;
1016 	list->count++;
1017 	return NDR_ERR_SUCCESS;
1018 }
1019 
1020 /*
1021   retrieve a token from a ndr context, using cmp_fn to match the tokens
1022 */
ndr_token_retrieve_cmp_fn(struct ndr_token_list * list,const void * key,uint32_t * v,comparison_fn_t _cmp_fn,bool erase)1023 _PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list,
1024 						     const void *key, uint32_t *v,
1025 						     comparison_fn_t _cmp_fn,
1026 						     bool erase)
1027 {
1028 	struct ndr_token *tokens = list->tokens;
1029 	unsigned i;
1030 	if (_cmp_fn) {
1031 		for (i = list->count - 1; i < list->count; i--) {
1032 			if (_cmp_fn(tokens[i].key, key) == 0) {
1033 				goto found;
1034 			}
1035 		}
1036 	} else {
1037 		for (i = list->count - 1; i < list->count; i--) {
1038 			if (tokens[i].key == key) {
1039 				goto found;
1040 			}
1041 		}
1042 	}
1043 	return NDR_ERR_TOKEN;
1044 found:
1045 	*v = tokens[i].value;
1046 	if (erase) {
1047 		if (i != list->count - 1) {
1048 			tokens[i] = tokens[list->count - 1];
1049 		}
1050 		list->count--;
1051 	}
1052 	return NDR_ERR_SUCCESS;
1053 }
1054 
1055 /*
1056   retrieve a token from a ndr context
1057 */
ndr_token_retrieve(struct ndr_token_list * list,const void * key,uint32_t * v)1058 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list,
1059 					      const void *key, uint32_t *v)
1060 {
1061 	return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
1062 }
1063 
1064 /*
1065   peek at but don't removed a token from a ndr context
1066 */
ndr_token_peek(struct ndr_token_list * list,const void * key)1067 _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list *list, const void *key)
1068 {
1069 	unsigned i;
1070 	struct ndr_token *tokens = list->tokens;
1071 
1072 	for (i = list->count - 1; i < list->count; i--) {
1073 		if (tokens[i].key == key) {
1074 			return tokens[i].value;
1075 		}
1076 	}
1077 
1078 	return 0;
1079 }
1080 
1081 /*
1082   pull an array size field and add it to the array_size_list token list
1083 */
ndr_pull_array_size(struct ndr_pull * ndr,const void * p)1084 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
1085 {
1086 	enum ndr_err_code ret;
1087 	uint32_t size;
1088 	NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
1089 	ret = ndr_token_store(ndr, &ndr->array_size_list, p, size);
1090 	if (ret == NDR_ERR_RANGE) {
1091 		return ndr_pull_error(ndr, ret,
1092 				      "More than %d NDR tokens stored for array_size",
1093 				      NDR_TOKEN_MAX_LIST_SIZE);
1094 	}
1095 	return ret;
1096 }
1097 
1098 /*
1099   get the stored array size field
1100 */
ndr_get_array_size(struct ndr_pull * ndr,const void * p)1101 _PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
1102 {
1103 	return ndr_token_peek(&ndr->array_size_list, p);
1104 }
1105 
1106 /*
1107   check the stored array size field
1108 */
ndr_check_array_size(struct ndr_pull * ndr,void * p,uint32_t size)1109 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
1110 {
1111 	uint32_t stored;
1112 	stored = ndr_token_peek(&ndr->array_size_list, p);
1113 	if (stored != size) {
1114 		return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1115 				      "Bad array size - got %u expected %u\n",
1116 				      stored, size);
1117 	}
1118 	return NDR_ERR_SUCCESS;
1119 }
1120 
1121 /*
1122   pull an array length field and add it to the array_length_list token list
1123 */
ndr_pull_array_length(struct ndr_pull * ndr,const void * p)1124 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1125 {
1126 	enum ndr_err_code ret;
1127 	uint32_t length, offset;
1128 	NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1129 	if (offset != 0) {
1130 		return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1131 				      "non-zero array offset %u\n", offset);
1132 	}
1133 	NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1134 	ret = ndr_token_store(ndr, &ndr->array_length_list, p, length);
1135 	if (ret == NDR_ERR_RANGE) {
1136 		return ndr_pull_error(ndr, ret,
1137 				      "More than %d NDR tokens stored for array_length_list",
1138 				      NDR_TOKEN_MAX_LIST_SIZE);
1139 	}
1140 	return ret;
1141 }
1142 
1143 /*
1144   get the stored array length field
1145 */
ndr_get_array_length(struct ndr_pull * ndr,const void * p)1146 _PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
1147 {
1148 	return ndr_token_peek(&ndr->array_length_list, p);
1149 }
1150 
1151 /*
1152   check the stored array length field
1153 */
ndr_check_array_length(struct ndr_pull * ndr,void * p,uint32_t length)1154 _PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
1155 {
1156 	uint32_t stored;
1157 	stored = ndr_token_peek(&ndr->array_length_list, p);
1158 	if (stored != length) {
1159 		return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1160 				      "Bad array length - got %u expected %u\n",
1161 				      stored, length);
1162 	}
1163 	return NDR_ERR_SUCCESS;
1164 }
1165 
ndr_push_pipe_chunk_trailer(struct ndr_push * ndr,int ndr_flags,uint32_t count)1166 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1167 {
1168 	if (ndr->flags & LIBNDR_FLAG_NDR64) {
1169 		int64_t tmp = 0 - (int64_t)count;
1170 		uint64_t ncount = tmp;
1171 
1172 		NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1173 	}
1174 
1175 	return NDR_ERR_SUCCESS;
1176 }
1177 
ndr_check_pipe_chunk_trailer(struct ndr_pull * ndr,int ndr_flags,uint32_t count)1178 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1179 {
1180 	if (ndr->flags & LIBNDR_FLAG_NDR64) {
1181 		int64_t tmp = 0 - (int64_t)count;
1182 		uint64_t ncount1 = tmp;
1183 		uint64_t ncount2;
1184 
1185 		NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1186 		if (ncount1 == ncount2) {
1187 			return NDR_ERR_SUCCESS;
1188 		}
1189 
1190 		return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1191 			"Bad pipe trailer[%lld should be %lld] size was %lu\"",
1192 			(unsigned long long)ncount2,
1193 			(unsigned long long)ncount1,
1194 			(unsigned long)count);
1195 	}
1196 
1197 	return NDR_ERR_SUCCESS;
1198 }
1199 
1200 /*
1201   store a switch value
1202  */
ndr_push_set_switch_value(struct ndr_push * ndr,const void * p,uint32_t val)1203 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1204 {
1205 	enum ndr_err_code ret =
1206 		ndr_token_store(ndr, &ndr->switch_list, p, val);
1207 	if (ret == NDR_ERR_RANGE) {
1208 		return ndr_push_error(ndr, ret,
1209 				      "More than %d NDR tokens stored for switch_list",
1210 				      NDR_TOKEN_MAX_LIST_SIZE);
1211 	}
1212 	return ret;
1213 }
1214 
ndr_pull_set_switch_value(struct ndr_pull * ndr,const void * p,uint32_t val)1215 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1216 {
1217 
1218 	enum ndr_err_code ret =
1219 		ndr_token_store(ndr, &ndr->switch_list, p, val);
1220 	if (ret == NDR_ERR_RANGE) {
1221 		return ndr_pull_error(ndr, ret,
1222 				      "More than %d NDR tokens stored for switch_list",
1223 				      NDR_TOKEN_MAX_LIST_SIZE);
1224 	}
1225 	return ret;
1226 }
1227 
ndr_print_set_switch_value(struct ndr_print * ndr,const void * p,uint32_t val)1228 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1229 {
1230 	return ndr_token_store(ndr, &ndr->switch_list, p, val);
1231 }
1232 
1233 /* retrieve a switch value (for push) and remove it from the list */
ndr_push_steal_switch_value(struct ndr_push * ndr,const void * p,uint32_t * v)1234 _PUBLIC_ enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr,
1235 						       const void *p,
1236 						       uint32_t *v)
1237 {
1238 	return ndr_token_retrieve(&ndr->switch_list, p, v);
1239 }
1240 
1241 /* retrieve a switch value and remove it from the list */
ndr_print_steal_switch_value(struct ndr_print * ndr,const void * p)1242 _PUBLIC_ uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p)
1243 {
1244 	enum ndr_err_code status;
1245 	uint32_t v;
1246 
1247 	status = ndr_token_retrieve(&ndr->switch_list, p, &v);
1248 	if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1249 		return 0;
1250 	}
1251 
1252 	return v;
1253 }
1254 
1255 /* retrieve a switch value and remove it from the list */
ndr_pull_steal_switch_value(struct ndr_pull * ndr,const void * p,uint32_t * v)1256 _PUBLIC_ enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr,
1257 						       const void *p,
1258 						       uint32_t *v)
1259 {
1260 	return ndr_token_retrieve(&ndr->switch_list, p, v);
1261 }
1262 
1263 /*
1264   pull a struct from a blob using NDR
1265 */
ndr_pull_struct_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,ndr_pull_flags_fn_t fn)1266 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1267 			      ndr_pull_flags_fn_t fn)
1268 {
1269 	struct ndr_pull *ndr;
1270 	ndr = ndr_pull_init_blob(blob, mem_ctx);
1271 	NDR_ERR_HAVE_NO_MEMORY(ndr);
1272 	NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1273 	talloc_free(ndr);
1274 	return NDR_ERR_SUCCESS;
1275 }
1276 
1277 /*
1278   pull a struct from a blob using NDR - failing if all bytes are not consumed
1279 */
ndr_pull_struct_blob_all(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,ndr_pull_flags_fn_t fn)1280 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1281 						    void *p, ndr_pull_flags_fn_t fn)
1282 {
1283 	struct ndr_pull *ndr;
1284 	uint32_t highest_ofs;
1285 	ndr = ndr_pull_init_blob(blob, mem_ctx);
1286 	NDR_ERR_HAVE_NO_MEMORY(ndr);
1287 	NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1288 	if (ndr->offset > ndr->relative_highest_offset) {
1289 		highest_ofs = ndr->offset;
1290 	} else {
1291 		highest_ofs = ndr->relative_highest_offset;
1292 	}
1293 	if (highest_ofs < ndr->data_size) {
1294 		enum ndr_err_code ret;
1295 		ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1296 				     "not all bytes consumed ofs[%u] size[%u]",
1297 				     highest_ofs, ndr->data_size);
1298 		talloc_free(ndr);
1299 		return ret;
1300 	}
1301 	talloc_free(ndr);
1302 	return NDR_ERR_SUCCESS;
1303 }
1304 
1305 /*
1306   pull a struct from a blob using NDR - failing if all bytes are not consumed
1307 
1308   This only works for structures with NO allocated memory, like
1309   objectSID and GUID.  This helps because we parse these a lot.
1310 */
ndr_pull_struct_blob_all_noalloc(const DATA_BLOB * blob,void * p,ndr_pull_flags_fn_t fn)1311 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
1312 							    void *p, ndr_pull_flags_fn_t fn)
1313 {
1314 	/*
1315 	 * We init this structure on the stack here, to avoid a
1316 	 * talloc() as otherwise this call to the fn() is assured not
1317 	 * to be doing any allocation, eg SIDs and GUIDs.
1318 	 *
1319 	 * This allows us to keep the safety of the PIDL-generated
1320 	 * code without the talloc() overhead.
1321 	 */
1322 	struct ndr_pull ndr = {
1323 		.data = blob->data,
1324 		.data_size = blob->length,
1325 		.current_mem_ctx = (void *)-1
1326 	};
1327 	uint32_t highest_ofs;
1328 	NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1329 	if (ndr.offset > ndr.relative_highest_offset) {
1330 		highest_ofs = ndr.offset;
1331 	} else {
1332 		highest_ofs = ndr.relative_highest_offset;
1333 	}
1334 	if (highest_ofs < ndr.data_size) {
1335 		enum ndr_err_code ret;
1336 		ret = ndr_pull_error(&ndr, NDR_ERR_UNREAD_BYTES,
1337 				     "not all bytes consumed ofs[%u] size[%u]",
1338 				     highest_ofs, ndr.data_size);
1339 		return ret;
1340 	}
1341 	return NDR_ERR_SUCCESS;
1342 }
1343 
1344 /*
1345   pull a union from a blob using NDR, given the union discriminator
1346 */
ndr_pull_union_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,uint32_t level,ndr_pull_flags_fn_t fn)1347 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1348 					       void *p,
1349 			     uint32_t level, ndr_pull_flags_fn_t fn)
1350 {
1351 	struct ndr_pull *ndr;
1352 	ndr = ndr_pull_init_blob(blob, mem_ctx);
1353 	NDR_ERR_HAVE_NO_MEMORY(ndr);
1354 	NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1355 	NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1356 	talloc_free(ndr);
1357 	return NDR_ERR_SUCCESS;
1358 }
1359 
1360 /*
1361   pull a union from a blob using NDR, given the union discriminator,
1362   failing if all bytes are not consumed
1363 */
ndr_pull_union_blob_all(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,uint32_t level,ndr_pull_flags_fn_t fn)1364 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1365 						   void *p,
1366 			     uint32_t level, ndr_pull_flags_fn_t fn)
1367 {
1368 	struct ndr_pull *ndr;
1369 	uint32_t highest_ofs;
1370 	ndr = ndr_pull_init_blob(blob, mem_ctx);
1371 	NDR_ERR_HAVE_NO_MEMORY(ndr);
1372 	NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1373 	NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1374 	if (ndr->offset > ndr->relative_highest_offset) {
1375 		highest_ofs = ndr->offset;
1376 	} else {
1377 		highest_ofs = ndr->relative_highest_offset;
1378 	}
1379 	if (highest_ofs < ndr->data_size) {
1380 		enum ndr_err_code ret;
1381 		ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1382 				     "not all bytes consumed ofs[%u] size[%u]",
1383 				     highest_ofs, ndr->data_size);
1384 		talloc_free(ndr);
1385 		return ret;
1386 	}
1387 	talloc_free(ndr);
1388 	return NDR_ERR_SUCCESS;
1389 }
1390 
1391 /*
1392   push a struct to a blob using NDR
1393 */
ndr_push_struct_blob(DATA_BLOB * blob,TALLOC_CTX * mem_ctx,const void * p,ndr_push_flags_fn_t fn)1394 _PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, ndr_push_flags_fn_t fn)
1395 {
1396 	struct ndr_push *ndr;
1397 	ndr = ndr_push_init_ctx(mem_ctx);
1398 	NDR_ERR_HAVE_NO_MEMORY(ndr);
1399 
1400 	NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1401 
1402 	*blob = ndr_push_blob(ndr);
1403 	talloc_steal(mem_ctx, blob->data);
1404 	talloc_free(ndr);
1405 
1406 	return NDR_ERR_SUCCESS;
1407 }
1408 
1409 /*
1410   push a struct into a provided blob using NDR.
1411 
1412   We error because we want to have the performance issue (extra
1413   talloc() calls) show up as an error, not just slower code.  This is
1414   used for things like GUIDs, which we expect to be a fixed size, and
1415   SIDs that we can pre-calculate the size for.
1416 */
ndr_push_struct_into_fixed_blob(DATA_BLOB * blob,const void * p,ndr_push_flags_fn_t fn)1417 _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
1418 	DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
1419 {
1420 	struct ndr_push ndr = {
1421 		.data = blob->data,
1422 		.alloc_size = blob->length,
1423 		.fixed_buf_size = true
1424 	};
1425 
1426 	NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1427 
1428 	if (ndr.offset != blob->length) {
1429 		return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
1430 				      "buffer was either to large or small "
1431 				      "ofs[%u] size[%zu]",
1432 				      ndr.offset, blob->length);
1433 	}
1434 
1435 	return NDR_ERR_SUCCESS;
1436 }
1437 
1438 /*
1439   push a union to a blob using NDR
1440 */
ndr_push_union_blob(DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,uint32_t level,ndr_push_flags_fn_t fn)1441 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1442 			     uint32_t level, ndr_push_flags_fn_t fn)
1443 {
1444 	struct ndr_push *ndr;
1445 	ndr = ndr_push_init_ctx(mem_ctx);
1446 	NDR_ERR_HAVE_NO_MEMORY(ndr);
1447 
1448 	NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1449 	NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1450 
1451 	*blob = ndr_push_blob(ndr);
1452 	talloc_steal(mem_ctx, blob->data);
1453 	talloc_free(ndr);
1454 
1455 	return NDR_ERR_SUCCESS;
1456 }
1457 
1458 /*
1459   generic ndr_size_*() handler for structures
1460 */
ndr_size_struct(const void * p,int flags,ndr_push_flags_fn_t push)1461 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1462 {
1463 	struct ndr_push *ndr;
1464 	enum ndr_err_code status;
1465 	size_t ret;
1466 
1467 	/* avoid recursion */
1468 	if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1469 
1470 	/* Avoid following a NULL pointer */
1471 	if (p == NULL) {
1472 		return 0;
1473 	}
1474 
1475 	ndr = ndr_push_init_ctx(NULL);
1476 	if (!ndr) return 0;
1477 	ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1478 	status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1479 	if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1480 		talloc_free(ndr);
1481 		return 0;
1482 	}
1483 	ret = ndr->offset;
1484 	talloc_free(ndr);
1485 	return ret;
1486 }
1487 
1488 /*
1489   generic ndr_size_*() handler for unions
1490 */
ndr_size_union(const void * p,int flags,uint32_t level,ndr_push_flags_fn_t push)1491 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1492 {
1493 	struct ndr_push *ndr;
1494 	enum ndr_err_code status;
1495 	size_t ret;
1496 
1497 	/* avoid recursion */
1498 	if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1499 
1500 	/* Avoid following a NULL pointer */
1501 	if (p == NULL) {
1502 		return 0;
1503 	}
1504 
1505 	ndr = ndr_push_init_ctx(NULL);
1506 	if (!ndr) return 0;
1507 	ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1508 
1509 	status = ndr_push_set_switch_value(ndr, p, level);
1510 	if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1511 		talloc_free(ndr);
1512 		return 0;
1513 	}
1514 	status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1515 	if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1516 		talloc_free(ndr);
1517 		return 0;
1518 	}
1519 	ret = ndr->offset;
1520 	talloc_free(ndr);
1521 	return ret;
1522 }
1523 
1524 /*
1525   get the current base for relative pointers for the push
1526 */
ndr_push_get_relative_base_offset(struct ndr_push * ndr)1527 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1528 {
1529 	return ndr->relative_base_offset;
1530 }
1531 
1532 /*
1533   restore the old base for relative pointers for the push
1534 */
ndr_push_restore_relative_base_offset(struct ndr_push * ndr,uint32_t offset)1535 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1536 {
1537 	ndr->relative_base_offset = offset;
1538 }
1539 
1540 /*
1541   setup the current base for relative pointers for the push
1542   called in the NDR_SCALAR stage
1543 */
ndr_push_setup_relative_base_offset1(struct ndr_push * ndr,const void * p,uint32_t offset)1544 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1545 {
1546 	enum ndr_err_code ret;
1547 	ndr->relative_base_offset = offset;
1548 	ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1549 	if (ret == NDR_ERR_RANGE) {
1550 		return ndr_push_error(ndr, ret,
1551 				      "More than %d NDR tokens stored for relative_base_list",
1552 				      NDR_TOKEN_MAX_LIST_SIZE);
1553 	}
1554 	return ret;
1555 }
1556 
1557 /*
1558   setup the current base for relative pointers for the push
1559   called in the NDR_BUFFERS stage
1560 */
ndr_push_setup_relative_base_offset2(struct ndr_push * ndr,const void * p)1561 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1562 {
1563 	return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1564 }
1565 
1566 /*
1567   push a relative object - stage1
1568   this is called during SCALARS processing
1569 */
ndr_push_relative_ptr1(struct ndr_push * ndr,const void * p)1570 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1571 {
1572 	enum ndr_err_code ret;
1573 	if (p == NULL) {
1574 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1575 		return NDR_ERR_SUCCESS;
1576 	}
1577 	NDR_CHECK(ndr_push_align(ndr, 4));
1578 	ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1579 	if (ret == NDR_ERR_RANGE) {
1580 		return ndr_push_error(ndr, ret,
1581 				      "More than %d NDR tokens stored for relative_list",
1582 				      NDR_TOKEN_MAX_LIST_SIZE);
1583 	}
1584 	NDR_CHECK(ret);
1585 	return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1586 }
1587 
1588 /*
1589   push a short relative object - stage1
1590   this is called during SCALARS processing
1591 */
ndr_push_short_relative_ptr1(struct ndr_push * ndr,const void * p)1592 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1593 {
1594 	enum ndr_err_code ret;
1595 	if (p == NULL) {
1596 		NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1597 		return NDR_ERR_SUCCESS;
1598 	}
1599 	NDR_CHECK(ndr_push_align(ndr, 2));
1600 	ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1601 	if (ret == NDR_ERR_RANGE) {
1602 		return ndr_push_error(ndr, ret,
1603 				      "More than %d NDR tokens stored for relative_list",
1604 				      NDR_TOKEN_MAX_LIST_SIZE);
1605 	}
1606 	NDR_CHECK(ret);
1607 	return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1608 }
1609 /*
1610   push a relative object - stage2
1611   this is called during buffers processing
1612 */
ndr_push_relative_ptr2(struct ndr_push * ndr,const void * p)1613 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1614 {
1615 	uint32_t save_offset;
1616 	uint32_t ptr_offset = 0xFFFFFFFF;
1617 	if (p == NULL) {
1618 		return NDR_ERR_SUCCESS;
1619 	}
1620 	save_offset = ndr->offset;
1621 	NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1622 	if (ptr_offset > ndr->offset) {
1623 		return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1624 				      "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1625 				      ptr_offset, ndr->offset);
1626 	}
1627 	ndr->offset = ptr_offset;
1628 	if (save_offset < ndr->relative_base_offset) {
1629 		return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1630 				      "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1631 				      save_offset, ndr->relative_base_offset);
1632 	}
1633 	NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1634 	ndr->offset = save_offset;
1635 	return NDR_ERR_SUCCESS;
1636 }
1637 /*
1638   push a short relative object - stage2
1639   this is called during buffers processing
1640 */
ndr_push_short_relative_ptr2(struct ndr_push * ndr,const void * p)1641 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1642 {
1643 	uint32_t save_offset;
1644 	uint32_t ptr_offset = 0xFFFF;
1645 	uint32_t relative_offset;
1646 	size_t pad;
1647 	size_t align = 1;
1648 
1649 	if (p == NULL) {
1650 		return NDR_ERR_SUCCESS;
1651 	}
1652 
1653 	if (ndr->offset < ndr->relative_base_offset) {
1654 		return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1655 				      "ndr_push_relative_ptr2 ndr->offset(%u) < ndr->relative_base_offset(%u)",
1656 				      ndr->offset, ndr->relative_base_offset);
1657 	}
1658 
1659 	relative_offset = ndr->offset - ndr->relative_base_offset;
1660 
1661 	if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1662 		align = 1;
1663 	} else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1664 		align = 2;
1665 	} else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1666 		align = 4;
1667 	} else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1668 		align = 8;
1669 	}
1670 
1671 	pad = ndr_align_size(relative_offset, align);
1672 	if (pad != 0) {
1673 		NDR_CHECK(ndr_push_zero(ndr, pad));
1674 	}
1675 
1676 	relative_offset = ndr->offset - ndr->relative_base_offset;
1677 	if (relative_offset > UINT16_MAX) {
1678 		return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1679 				      "ndr_push_relative_ptr2 relative_offset(%u) > UINT16_MAX",
1680 				      relative_offset);
1681 	}
1682 
1683 	save_offset = ndr->offset;
1684 	NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1685 	if (ptr_offset > ndr->offset) {
1686 		return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1687 				      "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1688 				      ptr_offset, ndr->offset);
1689 	}
1690 	ndr->offset = ptr_offset;
1691 	NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
1692 	ndr->offset = save_offset;
1693 	return NDR_ERR_SUCCESS;
1694 }
1695 
1696 /*
1697   push a relative object - stage2 start
1698   this is called during buffers processing
1699 */
ndr_push_relative_ptr2_start(struct ndr_push * ndr,const void * p)1700 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1701 {
1702 	enum ndr_err_code ret;
1703 	if (p == NULL) {
1704 		return NDR_ERR_SUCCESS;
1705 	}
1706 	if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1707 		uint32_t relative_offset;
1708 		size_t pad;
1709 		size_t align = 1;
1710 
1711 		if (ndr->offset < ndr->relative_base_offset) {
1712 			return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1713 				      "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1714 				      ndr->offset, ndr->relative_base_offset);
1715 		}
1716 
1717 		relative_offset = ndr->offset - ndr->relative_base_offset;
1718 
1719 		if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1720 			align = 1;
1721 		} else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1722 			align = 2;
1723 		} else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1724 			align = 4;
1725 		} else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1726 			align = 8;
1727 		}
1728 
1729 		pad = ndr_align_size(relative_offset, align);
1730 		if (pad) {
1731 			NDR_CHECK(ndr_push_zero(ndr, pad));
1732 		}
1733 
1734 		return ndr_push_relative_ptr2(ndr, p);
1735 	}
1736 	if (ndr->relative_end_offset == -1) {
1737 		return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1738 			      "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1739 			      ndr->relative_end_offset);
1740 	}
1741 	ret = ndr_token_store(ndr,
1742 			      &ndr->relative_begin_list,
1743 			      p,
1744 			      ndr->offset);
1745 	if (ret == NDR_ERR_RANGE) {
1746 		return ndr_push_error(ndr, ret,
1747 				      "More than %d NDR tokens stored for array_size",
1748 				      NDR_TOKEN_MAX_LIST_SIZE);
1749 	}
1750 	return ret;
1751 }
1752 
1753 /*
1754   push a relative object - stage2 end
1755   this is called during buffers processing
1756 */
ndr_push_relative_ptr2_end(struct ndr_push * ndr,const void * p)1757 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1758 {
1759 	uint32_t begin_offset = 0xFFFFFFFF;
1760 	ssize_t len;
1761 	uint32_t correct_offset = 0;
1762 	uint32_t align = 1;
1763 	uint32_t pad = 0;
1764 
1765 	if (p == NULL) {
1766 		return NDR_ERR_SUCCESS;
1767 	}
1768 
1769 	if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1770 		return NDR_ERR_SUCCESS;
1771 	}
1772 
1773 	if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1774 		/* better say more than calculation a too small buffer */
1775 		NDR_PUSH_ALIGN(ndr, 8);
1776 		return NDR_ERR_SUCCESS;
1777 	}
1778 
1779 	if (ndr->relative_end_offset < ndr->offset) {
1780 		return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1781 				      "ndr_push_relative_ptr2_end:"
1782 				      "relative_end_offset %u < offset %u",
1783 				      ndr->relative_end_offset, ndr->offset);
1784 	}
1785 
1786 	NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1787 
1788 	/* we have marshalled a buffer, see how long it was */
1789 	len = ndr->offset - begin_offset;
1790 
1791 	if (len < 0) {
1792 		return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1793 				      "ndr_push_relative_ptr2_end:"
1794 				      "offset %u - begin_offset %u < 0",
1795 				      ndr->offset, begin_offset);
1796 	}
1797 
1798 	if (ndr->relative_end_offset < len) {
1799 		return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1800 				      "ndr_push_relative_ptr2_end:"
1801 				      "relative_end_offset %u < len %lld",
1802 				      ndr->offset, (long long)len);
1803 	}
1804 
1805 	/* the reversed offset is at the end of the main buffer */
1806 	correct_offset = ndr->relative_end_offset - len;
1807 
1808 	if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1809 		align = 1;
1810 	} else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1811 		align = 2;
1812 	} else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1813 		align = 4;
1814 	} else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1815 		align = 8;
1816 	}
1817 
1818 	pad = ndr_align_size(correct_offset, align);
1819 	if (pad) {
1820 		correct_offset += pad;
1821 		correct_offset -= align;
1822 	}
1823 
1824 	if (correct_offset < begin_offset) {
1825 		return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1826 				      "ndr_push_relative_ptr2_end: "
1827 				      "correct_offset %u < begin_offset %u",
1828 				      correct_offset, begin_offset);
1829 	}
1830 
1831 	if (len > 0) {
1832 		uint32_t clear_size = correct_offset - begin_offset;
1833 
1834 		clear_size = MIN(clear_size, len);
1835 
1836 		/* now move the marshalled buffer to the end of the main buffer */
1837 		memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1838 
1839 		if (clear_size) {
1840 			/* and wipe out old buffer within the main buffer */
1841 			memset(ndr->data + begin_offset, '\0', clear_size);
1842 		}
1843 	}
1844 
1845 	/* and set the end offset for the next buffer */
1846 	ndr->relative_end_offset = correct_offset;
1847 
1848 	/* finally write the offset to the main buffer */
1849 	ndr->offset = correct_offset;
1850 	NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1851 
1852 	/* restore to where we were in the main buffer */
1853 	ndr->offset = begin_offset;
1854 
1855 	return NDR_ERR_SUCCESS;
1856 }
1857 
1858 /*
1859   get the current base for relative pointers for the pull
1860 */
ndr_pull_get_relative_base_offset(struct ndr_pull * ndr)1861 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1862 {
1863 	return ndr->relative_base_offset;
1864 }
1865 
1866 /*
1867   restore the old base for relative pointers for the pull
1868 */
ndr_pull_restore_relative_base_offset(struct ndr_pull * ndr,uint32_t offset)1869 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1870 {
1871 	ndr->relative_base_offset = offset;
1872 }
1873 
1874 /*
1875   setup the current base for relative pointers for the pull
1876   called in the NDR_SCALAR stage
1877 */
ndr_pull_setup_relative_base_offset1(struct ndr_pull * ndr,const void * p,uint32_t offset)1878 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1879 {
1880 	enum ndr_err_code ret;
1881 	ndr->relative_base_offset = offset;
1882 	ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1883 	if (ret == NDR_ERR_RANGE) {
1884 		return ndr_pull_error(ndr, ret,
1885 				      "More than %d NDR tokens stored for relative_base_list",
1886 				      NDR_TOKEN_MAX_LIST_SIZE);
1887 	}
1888 	return ret;
1889 }
1890 
1891 /*
1892   setup the current base for relative pointers for the pull
1893   called in the NDR_BUFFERS stage
1894 */
ndr_pull_setup_relative_base_offset2(struct ndr_pull * ndr,const void * p)1895 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1896 {
1897 	return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1898 }
1899 
1900 /*
1901   pull a relative object - stage1
1902   called during SCALARS processing
1903 */
ndr_pull_relative_ptr1(struct ndr_pull * ndr,const void * p,uint32_t rel_offset)1904 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1905 {
1906 	enum ndr_err_code ret;
1907 	rel_offset += ndr->relative_base_offset;
1908 	if (rel_offset > ndr->data_size) {
1909 		return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1910 				      "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1911 				      rel_offset, ndr->data_size);
1912 	}
1913 	ret = ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1914 	if (ret == NDR_ERR_RANGE) {
1915 		return ndr_pull_error(ndr, ret,
1916 				      "More than %d NDR tokens stored for relative_list",
1917 				      NDR_TOKEN_MAX_LIST_SIZE);
1918 	}
1919 	return ret;
1920 }
1921 
1922 /*
1923   pull a relative object - stage2
1924   called during BUFFERS processing
1925 */
ndr_pull_relative_ptr2(struct ndr_pull * ndr,const void * p)1926 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1927 {
1928 	uint32_t rel_offset;
1929 	NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1930 	return ndr_pull_set_offset(ndr, rel_offset);
1931 }
1932 
1933 const static struct {
1934 	enum ndr_err_code err;
1935 	const char *string;
1936 } ndr_err_code_strings[] = {
1937 	{ NDR_ERR_SUCCESS, "Success" },
1938 	{ NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1939 	{ NDR_ERR_BAD_SWITCH, "Bad Switch" },
1940 	{ NDR_ERR_OFFSET, "Offset Error" },
1941 	{ NDR_ERR_RELATIVE, "Relative Pointer Error" },
1942 	{ NDR_ERR_CHARCNV, "Character Conversion Error" },
1943 	{ NDR_ERR_LENGTH, "Length Error" },
1944 	{ NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1945 	{ NDR_ERR_COMPRESSION, "Compression Error" },
1946 	{ NDR_ERR_STRING, "String Error" },
1947 	{ NDR_ERR_VALIDATE, "Validate Error" },
1948 	{ NDR_ERR_BUFSIZE, "Buffer Size Error" },
1949 	{ NDR_ERR_ALLOC, "Allocation Error" },
1950 	{ NDR_ERR_RANGE, "Range Error" },
1951 	{ NDR_ERR_TOKEN, "Token Error" },
1952 	{ NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1953 	{ NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1954 	{ NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1955 	{ NDR_ERR_NDR64, "NDR64 assertion error" },
1956 	{ NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
1957 	{ 0, NULL }
1958 };
1959 
ndr_map_error2string(enum ndr_err_code ndr_err)1960 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1961 {
1962 	int i;
1963 	for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
1964 		if (ndr_err_code_strings[i].err == ndr_err)
1965 			return ndr_err_code_strings[i].string;
1966 	}
1967 	return "Unknown error";
1968 }
1969