1 /*
2    Unix SMB/CIFS implementation.
3 
4    libndr interface
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 /*
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 #include "librpc/gen_ndr/dcerpc.h"
34 
35 #define NDR_BASE_MARSHALL_SIZE 1024
36 
37 /* this guid indicates NDR encoding in a protocol tower */
38 const struct dcerpc_syntax_id ndr_transfer_syntax = {
39   { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
40   2
41 };
42 
43 const struct dcerpc_syntax_id ndr64_transfer_syntax = {
44   { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
45   1
46 };
47 
48 /*
49   work out the number of bytes needed to align on a n byte boundary
50 */
ndr_align_size(uint32_t offset,size_t n)51 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
52 {
53 	if ((offset & (n-1)) == 0) return 0;
54 	return n - (offset & (n-1));
55 }
56 
57 /*
58   initialise a ndr parse structure from a data blob
59 */
ndr_pull_init_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx)60 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
61 {
62 	struct ndr_pull *ndr;
63 
64 	ndr = talloc_zero(mem_ctx, struct ndr_pull);
65 	if (!ndr) return NULL;
66 	ndr->current_mem_ctx = mem_ctx;
67 
68 	ndr->data = blob->data;
69 	ndr->data_size = blob->length;
70 
71 	return ndr;
72 }
73 
74 /*
75   advance by 'size' bytes
76 */
ndr_pull_advance(struct ndr_pull * ndr,uint32_t size)77 _PUBLIC_ NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
78 {
79 	ndr->offset += size;
80 	if (ndr->offset > ndr->data_size) {
81 		return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
82 				      "ndr_pull_advance by %u failed",
83 				      size);
84 	}
85 	return NT_STATUS_OK;
86 }
87 
88 /*
89   set the parse offset to 'ofs'
90 */
ndr_pull_set_offset(struct ndr_pull * ndr,uint32_t ofs)91 static NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
92 {
93 	ndr->offset = ofs;
94 	if (ndr->offset > ndr->data_size) {
95 		return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
96 				      "ndr_pull_set_offset %u failed",
97 				      ofs);
98 	}
99 	return NT_STATUS_OK;
100 }
101 
102 /* save the offset/size of the current ndr state */
ndr_pull_save(struct ndr_pull * ndr,struct ndr_pull_save * save)103 _PUBLIC_ void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save)
104 {
105 	save->offset = ndr->offset;
106 	save->data_size = ndr->data_size;
107 }
108 
109 /* restore the size/offset of a ndr structure */
ndr_pull_restore(struct ndr_pull * ndr,struct ndr_pull_save * save)110 _PUBLIC_ void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
111 {
112 	ndr->offset = save->offset;
113 	ndr->data_size = save->data_size;
114 }
115 
116 
117 /* create a ndr_push structure, ready for some marshalling */
ndr_push_init_ctx(TALLOC_CTX * mem_ctx)118 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
119 {
120 	struct ndr_push *ndr;
121 
122 	ndr = talloc_zero(mem_ctx, struct ndr_push);
123 	if (!ndr) {
124 		return NULL;
125 	}
126 
127 	ndr->flags = 0;
128 	ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
129 	ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
130 	if (!ndr->data) {
131 		return NULL;
132 	}
133 
134 	return ndr;
135 }
136 
137 
138 /* create a ndr_push structure, ready for some marshalling */
ndr_push_init(void)139 _PUBLIC_ struct ndr_push *ndr_push_init(void)
140 {
141 	return ndr_push_init_ctx(NULL);
142 }
143 
144 /* free a ndr_push structure */
ndr_push_free(struct ndr_push * ndr)145 _PUBLIC_ void ndr_push_free(struct ndr_push *ndr)
146 {
147 	talloc_free(ndr);
148 }
149 
150 
151 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
ndr_push_blob(struct ndr_push * ndr)152 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
153 {
154 	DATA_BLOB blob;
155 	blob.data = ndr->data;
156 	blob.length = ndr->offset;
157 	if (ndr->alloc_size > ndr->offset) {
158 		ndr->data[ndr->offset] = 0;
159 	}
160 	return blob;
161 }
162 
163 
164 /*
165   expand the available space in the buffer to 'size'
166 */
ndr_push_expand(struct ndr_push * ndr,uint32_t size)167 _PUBLIC_ NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32_t size)
168 {
169 	if (ndr->alloc_size > size) {
170 		return NT_STATUS_OK;
171 	}
172 
173 	ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
174 	if (size+1 > ndr->alloc_size) {
175 		ndr->alloc_size = size+1;
176 	}
177 	ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
178 	if (!ndr->data) {
179 		return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
180 				      ndr->alloc_size);
181 	}
182 
183 	return NT_STATUS_OK;
184 }
185 
ndr_print_debug_helper(struct ndr_print * ndr,const char * format,...)186 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
187 {
188 	va_list ap;
189 	char *s = NULL;
190 	int i;
191 
192 	va_start(ap, format);
193 	vasprintf(&s, format, ap);
194 	va_end(ap);
195 
196 	for (i=0;i<ndr->depth;i++) {
197 		DEBUG(0,("    "));
198 	}
199 
200 	DEBUG(0,("%s\n", s));
201 	free(s);
202 }
203 
ndr_print_string_helper(struct ndr_print * ndr,const char * format,...)204 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
205 {
206 	va_list ap;
207 	int i;
208 
209 	for (i=0;i<ndr->depth;i++) {
210 		ndr->private_data = talloc_asprintf_append(ndr->private_data, "    ");
211 	}
212 
213 	va_start(ap, format);
214 	ndr->private_data = talloc_vasprintf_append(ndr->private_data, format, ap);
215 	va_end(ap);
216 	ndr->private_data = talloc_asprintf_append(ndr->private_data, "\n");
217 }
218 
219 /*
220   a useful helper function for printing idl structures via DEBUG()
221 */
ndr_print_debug(ndr_print_fn_t fn,const char * name,void * ptr)222 _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
223 {
224 	struct ndr_print *ndr;
225 
226 	ndr = talloc_zero(NULL, struct ndr_print);
227 	if (!ndr) return;
228 	ndr->print = ndr_print_debug_helper;
229 	ndr->depth = 1;
230 	ndr->flags = 0;
231 	fn(ndr, name, ptr);
232 	talloc_free(ndr);
233 }
234 
235 /*
236   a useful helper function for printing idl unions via DEBUG()
237 */
ndr_print_union_debug(ndr_print_fn_t fn,const char * name,uint32_t level,void * ptr)238 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
239 {
240 	struct ndr_print *ndr;
241 
242 	ndr = talloc_zero(NULL, struct ndr_print);
243 	if (!ndr) return;
244 	ndr->print = ndr_print_debug_helper;
245 	ndr->depth = 1;
246 	ndr->flags = 0;
247 	ndr_print_set_switch_value(ndr, ptr, level);
248 	fn(ndr, name, ptr);
249 	talloc_free(ndr);
250 }
251 
252 /*
253   a useful helper function for printing idl function calls via DEBUG()
254 */
ndr_print_function_debug(ndr_print_function_t fn,const char * name,int flags,void * ptr)255 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
256 {
257 	struct ndr_print *ndr;
258 
259 	ndr = talloc_zero(NULL, struct ndr_print);
260 	if (!ndr) return;
261 	ndr->print = ndr_print_debug_helper;
262 	ndr->depth = 1;
263 	ndr->flags = 0;
264 	fn(ndr, name, flags, ptr);
265 	talloc_free(ndr);
266 }
267 
268 /*
269   a useful helper function for printing idl structures to a string
270 */
ndr_print_struct_string(TALLOC_CTX * mem_ctx,ndr_print_fn_t fn,const char * name,void * ptr)271 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
272 {
273 	struct ndr_print *ndr;
274 	char *ret = NULL;
275 
276 	ndr = talloc_zero(mem_ctx, struct ndr_print);
277 	if (!ndr) return NULL;
278 	ndr->private_data = talloc_strdup(ndr, "");
279 	if (!ndr->private_data) {
280 		goto failed;
281 	}
282 	ndr->print = ndr_print_string_helper;
283 	ndr->depth = 1;
284 	ndr->flags = 0;
285 	fn(ndr, name, ptr);
286 	ret = talloc_steal(mem_ctx, ndr->private_data);
287 failed:
288 	talloc_free(ndr);
289 	return ret;
290 }
291 
292 /*
293   a useful helper function for printing idl unions to a string
294 */
ndr_print_union_string(TALLOC_CTX * mem_ctx,ndr_print_fn_t fn,const char * name,uint32_t level,void * ptr)295 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
296 {
297 	struct ndr_print *ndr;
298 	char *ret = NULL;
299 
300 	ndr = talloc_zero(mem_ctx, struct ndr_print);
301 	if (!ndr) return NULL;
302 	ndr->private_data = talloc_strdup(ndr, "");
303 	if (!ndr->private_data) {
304 		goto failed;
305 	}
306 	ndr->print = ndr_print_string_helper;
307 	ndr->depth = 1;
308 	ndr->flags = 0;
309 	ndr_print_set_switch_value(ndr, ptr, level);
310 	fn(ndr, name, ptr);
311 	ret = talloc_steal(mem_ctx, ndr->private_data);
312 failed:
313 	talloc_free(ndr);
314 	return ret;
315 }
316 
317 /*
318   a useful helper function for printing idl function calls to a string
319 */
ndr_print_function_string(TALLOC_CTX * mem_ctx,ndr_print_function_t fn,const char * name,int flags,void * ptr)320 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
321 				ndr_print_function_t fn, const char *name,
322 				int flags, void *ptr)
323 {
324 	struct ndr_print *ndr;
325 	char *ret = NULL;
326 
327 	ndr = talloc_zero(mem_ctx, struct ndr_print);
328 	if (!ndr) return NULL;
329 	ndr->private_data = talloc_strdup(ndr, "");
330 	if (!ndr->private_data) {
331 		goto failed;
332 	}
333 	ndr->print = ndr_print_string_helper;
334 	ndr->depth = 1;
335 	ndr->flags = 0;
336 	fn(ndr, name, flags, ptr);
337 	ret = talloc_steal(mem_ctx, ndr->private_data);
338 failed:
339 	talloc_free(ndr);
340 	return ret;
341 }
342 
ndr_set_flags(uint32_t * pflags,uint32_t new_flags)343 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
344 {
345 	/* the big/little endian flags are inter-dependent */
346 	if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
347 		(*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
348 	}
349 	if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
350 		(*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
351 	}
352 	if (new_flags & LIBNDR_FLAG_REMAINING) {
353 		(*pflags) &= ~LIBNDR_ALIGN_FLAGS;
354 	}
355 	if (new_flags & LIBNDR_ALIGN_FLAGS) {
356 		(*pflags) &= ~LIBNDR_FLAG_REMAINING;
357 	}
358 	(*pflags) |= new_flags;
359 }
360 
ndr_map_error(enum ndr_err_code ndr_err)361 static NTSTATUS ndr_map_error(enum ndr_err_code ndr_err)
362 {
363 	switch (ndr_err) {
364 	case NDR_ERR_BUFSIZE:
365 		return NT_STATUS_BUFFER_TOO_SMALL;
366 	case NDR_ERR_TOKEN:
367 		return NT_STATUS_INTERNAL_ERROR;
368 	case NDR_ERR_ALLOC:
369 		return NT_STATUS_NO_MEMORY;
370 	case NDR_ERR_ARRAY_SIZE:
371 		return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
372 	default:
373 		break;
374 	}
375 
376 	/* we should map all error codes to different status codes */
377 	return NT_STATUS_INVALID_PARAMETER;
378 }
379 
380 /*
381   return and possibly log an NDR error
382 */
ndr_pull_error(struct ndr_pull * ndr,enum ndr_err_code ndr_err,const char * format,...)383 _PUBLIC_ NTSTATUS ndr_pull_error(struct ndr_pull *ndr,
384 				 enum ndr_err_code ndr_err,
385 				 const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
386 {
387 	char *s=NULL;
388 	va_list ap;
389 
390 	va_start(ap, format);
391 	vasprintf(&s, format, ap);
392 	va_end(ap);
393 
394 	DEBUG(3,("ndr_pull_error(%u): %s\n", ndr_err, s));
395 
396 	free(s);
397 
398 	return ndr_map_error(ndr_err);
399 }
400 
401 /*
402   return and possibly log an NDR error
403 */
ndr_push_error(struct ndr_push * ndr,enum ndr_err_code ndr_err,const char * format,...)404 _PUBLIC_ NTSTATUS ndr_push_error(struct ndr_push *ndr,
405 				 enum ndr_err_code ndr_err,
406 				 const char *format, ...)  _PRINTF_ATTRIBUTE(3,4)
407 {
408 	char *s=NULL;
409 	va_list ap;
410 
411 	va_start(ap, format);
412 	vasprintf(&s, format, ap);
413 	va_end(ap);
414 
415 	DEBUG(3,("ndr_push_error(%u): %s\n", ndr_err, s));
416 
417 	free(s);
418 
419 	return ndr_map_error(ndr_err);
420 }
421 
422 /*
423   handle subcontext buffers, which in midl land are user-marshalled, but
424   we use magic in pidl to make them easier to cope with
425 */
ndr_pull_subcontext_start(struct ndr_pull * ndr,struct ndr_pull ** _subndr,size_t header_size,ssize_t size_is)426 _PUBLIC_ NTSTATUS ndr_pull_subcontext_start(struct ndr_pull *ndr,
427 				   struct ndr_pull **_subndr,
428 				   size_t header_size,
429 				   ssize_t size_is)
430 {
431 	struct ndr_pull *subndr;
432 	uint32_t r_content_size;
433 
434 	switch (header_size) {
435 	case 0: {
436 		uint32_t content_size = ndr->data_size - ndr->offset;
437 		if (size_is >= 0) {
438 			content_size = size_is;
439 		}
440 		r_content_size = content_size;
441 		break;
442 	}
443 
444 	case 2: {
445 		uint16_t content_size;
446 		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
447 		if (size_is >= 0 && size_is != content_size) {
448 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
449 						(int)size_is, (int)content_size);
450 		}
451 		r_content_size = content_size;
452 		break;
453 	}
454 
455 	case 4: {
456 		uint32_t content_size;
457 		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
458 		if (size_is >= 0 && size_is != content_size) {
459 			return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
460 						(int)size_is, (int)content_size);
461 		}
462 		r_content_size = content_size;
463 		break;
464 	}
465 	default:
466 		return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
467 				      (int)header_size);
468 	}
469 
470 	NDR_PULL_NEED_BYTES(ndr, r_content_size);
471 
472 	subndr = talloc_zero(ndr, struct ndr_pull);
473 	NT_STATUS_HAVE_NO_MEMORY(subndr);
474 	subndr->flags		= ndr->flags;
475 	subndr->current_mem_ctx	= ndr->current_mem_ctx;
476 
477 	subndr->data = ndr->data + ndr->offset;
478 	subndr->offset = 0;
479 	subndr->data_size = r_content_size;
480 
481 	*_subndr = subndr;
482 	return NT_STATUS_OK;
483 }
484 
ndr_pull_subcontext_end(struct ndr_pull * ndr,struct ndr_pull * subndr,size_t header_size,ssize_t size_is)485 _PUBLIC_ NTSTATUS ndr_pull_subcontext_end(struct ndr_pull *ndr,
486 				 struct ndr_pull *subndr,
487 				 size_t header_size,
488 				 ssize_t size_is)
489 {
490 	uint32_t advance;
491 	if (size_is >= 0) {
492 		advance = size_is;
493 	} else if (header_size > 0) {
494 		advance = subndr->data_size;
495 	} else {
496 		advance = subndr->offset;
497 	}
498 	NDR_CHECK(ndr_pull_advance(ndr, advance));
499 	return NT_STATUS_OK;
500 }
501 
ndr_push_subcontext_start(struct ndr_push * ndr,struct ndr_push ** _subndr,size_t header_size,ssize_t size_is)502 _PUBLIC_ NTSTATUS ndr_push_subcontext_start(struct ndr_push *ndr,
503 				   struct ndr_push **_subndr,
504 				   size_t header_size,
505 				   ssize_t size_is)
506 {
507 	struct ndr_push *subndr;
508 
509 	subndr = ndr_push_init_ctx(ndr);
510 	NT_STATUS_HAVE_NO_MEMORY(subndr);
511 	subndr->flags	= ndr->flags;
512 
513 	*_subndr = subndr;
514 	return NT_STATUS_OK;
515 }
516 
517 /*
518   push a subcontext header
519 */
ndr_push_subcontext_end(struct ndr_push * ndr,struct ndr_push * subndr,size_t header_size,ssize_t size_is)520 _PUBLIC_ NTSTATUS ndr_push_subcontext_end(struct ndr_push *ndr,
521 				 struct ndr_push *subndr,
522 				 size_t header_size,
523 				 ssize_t size_is)
524 {
525 	if (size_is >= 0) {
526 		ssize_t padding_len = size_is - subndr->offset;
527 		if (padding_len > 0) {
528 			NDR_CHECK(ndr_push_zero(subndr, padding_len));
529 		} else if (padding_len < 0) {
530 			return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
531 					      (int)subndr->offset, (int)size_is);
532 		}
533 	}
534 
535 	switch (header_size) {
536 	case 0:
537 		break;
538 
539 	case 2:
540 		NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
541 		break;
542 
543 	case 4:
544 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
545 		break;
546 
547 	default:
548 		return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
549 				      (int)header_size);
550 	}
551 
552 	NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
553 	return NT_STATUS_OK;
554 }
555 
556 /*
557   store a token in the ndr context, for later retrieval
558 */
ndr_token_store(TALLOC_CTX * mem_ctx,struct ndr_token_list ** list,const void * key,uint32_t value)559 _PUBLIC_ NTSTATUS ndr_token_store(TALLOC_CTX *mem_ctx,
560 			 struct ndr_token_list **list,
561 			 const void *key,
562 			 uint32_t value)
563 {
564 	struct ndr_token_list *tok;
565 	tok = talloc(mem_ctx, struct ndr_token_list);
566 	if (tok == NULL) {
567 		return NT_STATUS_NO_MEMORY;
568 	}
569 	tok->key = key;
570 	tok->value = value;
571 	DLIST_ADD((*list), tok);
572 	return NT_STATUS_OK;
573 }
574 
575 /*
576   retrieve a token from a ndr context, using cmp_fn to match the tokens
577 */
ndr_token_retrieve_cmp_fn(struct ndr_token_list ** list,const void * key,uint32_t * v,comparison_fn_t _cmp_fn,BOOL _remove_tok)578 _PUBLIC_ NTSTATUS ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v,
579 				   comparison_fn_t _cmp_fn, BOOL _remove_tok)
580 {
581 	struct ndr_token_list *tok;
582 	for (tok=*list;tok;tok=tok->next) {
583 		if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found;
584 		else if (!_cmp_fn && tok->key == key) goto found;
585 	}
586 	return ndr_map_error(NDR_ERR_TOKEN);
587 found:
588 	*v = tok->value;
589 	if (_remove_tok) {
590 		DLIST_REMOVE((*list), tok);
591 		talloc_free(tok);
592 	}
593 	return NT_STATUS_OK;
594 }
595 
596 /*
597   retrieve a token from a ndr context
598 */
ndr_token_retrieve(struct ndr_token_list ** list,const void * key,uint32_t * v)599 _PUBLIC_ NTSTATUS ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
600 {
601 	return ndr_token_retrieve_cmp_fn(list, key, v, NULL, True);
602 }
603 
604 /*
605   peek at but don't removed a token from a ndr context
606 */
ndr_token_peek(struct ndr_token_list ** list,const void * key)607 _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
608 {
609 	NTSTATUS status;
610 	uint32_t v;
611 	status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, False);
612 	if (NT_STATUS_IS_OK(status)) return v;
613 	return 0;
614 }
615 
616 /*
617   pull an array size field and add it to the array_size_list token list
618 */
ndr_pull_array_size(struct ndr_pull * ndr,const void * p)619 _PUBLIC_ NTSTATUS ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
620 {
621 	uint32_t size;
622 	NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size));
623 	return ndr_token_store(ndr, &ndr->array_size_list, p, size);
624 }
625 
626 /*
627   get the stored array size field
628 */
ndr_get_array_size(struct ndr_pull * ndr,const void * p)629 _PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
630 {
631 	return ndr_token_peek(&ndr->array_size_list, p);
632 }
633 
634 /*
635   check the stored array size field
636 */
ndr_check_array_size(struct ndr_pull * ndr,void * p,uint32_t size)637 _PUBLIC_ NTSTATUS ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
638 {
639 	uint32_t stored;
640 	stored = ndr_token_peek(&ndr->array_size_list, p);
641 	if (stored != size) {
642 		return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
643 				      "Bad array size - got %u expected %u\n",
644 				      stored, size);
645 	}
646 	return NT_STATUS_OK;
647 }
648 
649 /*
650   pull an array length field and add it to the array_length_list token list
651 */
ndr_pull_array_length(struct ndr_pull * ndr,const void * p)652 _PUBLIC_ NTSTATUS ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
653 {
654 	uint32_t length, offset;
655 	NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &offset));
656 	if (offset != 0) {
657 		return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
658 				      "non-zero array offset %u\n", offset);
659 	}
660 	NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length));
661 	return ndr_token_store(ndr, &ndr->array_length_list, p, length);
662 }
663 
664 /*
665   get the stored array length field
666 */
ndr_get_array_length(struct ndr_pull * ndr,const void * p)667 _PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
668 {
669 	return ndr_token_peek(&ndr->array_length_list, p);
670 }
671 
672 /*
673   check the stored array length field
674 */
ndr_check_array_length(struct ndr_pull * ndr,void * p,uint32_t length)675 _PUBLIC_ NTSTATUS ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
676 {
677 	uint32_t stored;
678 	stored = ndr_token_peek(&ndr->array_length_list, p);
679 	if (stored != length) {
680 		return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
681 				      "Bad array length - got %u expected %u\n",
682 				      stored, length);
683 	}
684 	return NT_STATUS_OK;
685 }
686 
687 /*
688   store a switch value
689  */
ndr_push_set_switch_value(struct ndr_push * ndr,const void * p,uint32_t val)690 _PUBLIC_ NTSTATUS ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
691 {
692 	return ndr_token_store(ndr, &ndr->switch_list, p, val);
693 }
694 
ndr_pull_set_switch_value(struct ndr_pull * ndr,const void * p,uint32_t val)695 _PUBLIC_ NTSTATUS ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
696 {
697 	return ndr_token_store(ndr, &ndr->switch_list, p, val);
698 }
699 
ndr_print_set_switch_value(struct ndr_print * ndr,const void * p,uint32_t val)700 _PUBLIC_ NTSTATUS ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
701 {
702 	return ndr_token_store(ndr, &ndr->switch_list, p, val);
703 }
704 
705 /*
706   retrieve a switch value
707  */
ndr_push_get_switch_value(struct ndr_push * ndr,const void * p)708 _PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
709 {
710 	return ndr_token_peek(&ndr->switch_list, p);
711 }
712 
ndr_pull_get_switch_value(struct ndr_pull * ndr,const void * p)713 _PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
714 {
715 	return ndr_token_peek(&ndr->switch_list, p);
716 }
717 
ndr_print_get_switch_value(struct ndr_print * ndr,const void * p)718 _PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
719 {
720 	return ndr_token_peek(&ndr->switch_list, p);
721 }
722 
723 /*
724   pull a struct from a blob using NDR
725 */
ndr_pull_struct_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,ndr_pull_flags_fn_t fn)726 _PUBLIC_ NTSTATUS ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
727 			      ndr_pull_flags_fn_t fn)
728 {
729 	struct ndr_pull *ndr;
730 	ndr = ndr_pull_init_blob(blob, mem_ctx);
731 	if (!ndr) {
732 		return NT_STATUS_NO_MEMORY;
733 	}
734 	return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
735 }
736 
737 /*
738   pull a struct from a blob using NDR - failing if all bytes are not consumed
739 */
ndr_pull_struct_blob_all(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,ndr_pull_flags_fn_t fn)740 _PUBLIC_ NTSTATUS ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
741 				  ndr_pull_flags_fn_t fn)
742 {
743 	struct ndr_pull *ndr;
744 	NTSTATUS status;
745 
746 	ndr = ndr_pull_init_blob(blob, mem_ctx);
747 	if (!ndr) {
748 		return NT_STATUS_NO_MEMORY;
749 	}
750 	status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
751 	if (!NT_STATUS_IS_OK(status)) return status;
752 	if (ndr->offset != ndr->data_size) {
753 		return NT_STATUS_BUFFER_TOO_SMALL;
754 	}
755 	return status;
756 }
757 
758 /*
759   pull a union from a blob using NDR, given the union discriminator
760 */
ndr_pull_union_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,uint32_t level,ndr_pull_flags_fn_t fn)761 _PUBLIC_ NTSTATUS ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
762 			     uint32_t level, ndr_pull_flags_fn_t fn)
763 {
764 	struct ndr_pull *ndr;
765 	NTSTATUS status;
766 
767 	ndr = ndr_pull_init_blob(blob, mem_ctx);
768 	if (!ndr) {
769 		return NT_STATUS_NO_MEMORY;
770 	}
771 	ndr_pull_set_switch_value(ndr, p, level);
772 	status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
773 	if (!NT_STATUS_IS_OK(status)) return status;
774 	if (ndr->offset != ndr->data_size) {
775 		return NT_STATUS_BUFFER_TOO_SMALL;
776 	}
777 	return status;
778 }
779 
780 /*
781   push a struct to a blob using NDR
782 */
ndr_push_struct_blob(DATA_BLOB * blob,TALLOC_CTX * mem_ctx,const void * p,ndr_push_flags_fn_t fn)783 _PUBLIC_ NTSTATUS ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p,
784 			      ndr_push_flags_fn_t fn)
785 {
786 	NTSTATUS status;
787 	struct ndr_push *ndr;
788 	ndr = ndr_push_init_ctx(mem_ctx);
789 	if (!ndr) {
790 		return NT_STATUS_NO_MEMORY;
791 	}
792 	status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
793 	if (!NT_STATUS_IS_OK(status)) {
794 		return status;
795 	}
796 
797 	*blob = ndr_push_blob(ndr);
798 	talloc_steal(mem_ctx, blob->data);
799 	talloc_free(ndr);
800 
801 	return NT_STATUS_OK;
802 }
803 
804 /*
805   push a union to a blob using NDR
806 */
ndr_push_union_blob(DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,uint32_t level,ndr_push_flags_fn_t fn)807 _PUBLIC_ NTSTATUS ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
808 			     uint32_t level, ndr_push_flags_fn_t fn)
809 {
810 	NTSTATUS status;
811 	struct ndr_push *ndr;
812 	ndr = ndr_push_init_ctx(mem_ctx);
813 	if (!ndr) {
814 		return NT_STATUS_NO_MEMORY;
815 	}
816 	ndr_push_set_switch_value(ndr, p, level);
817 	status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
818 	if (!NT_STATUS_IS_OK(status)) {
819 		return status;
820 	}
821 
822 	*blob = ndr_push_blob(ndr);
823 	talloc_steal(mem_ctx, blob->data);
824 	talloc_free(ndr);
825 
826 	return NT_STATUS_OK;
827 }
828 
829 /*
830   generic ndr_size_*() handler for structures
831 */
ndr_size_struct(const void * p,int flags,ndr_push_flags_fn_t push)832 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
833 {
834 	struct ndr_push *ndr;
835 	NTSTATUS status;
836 	size_t ret;
837 
838 	/* avoid recursion */
839 	if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
840 
841 	ndr = ndr_push_init_ctx(NULL);
842 	if (!ndr) return 0;
843 	ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
844 	status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
845 	if (!NT_STATUS_IS_OK(status)) {
846 		return 0;
847 	}
848 	ret = ndr->offset;
849 	talloc_free(ndr);
850 	return ret;
851 }
852 
853 /*
854   generic ndr_size_*() handler for unions
855 */
ndr_size_union(const void * p,int flags,uint32_t level,ndr_push_flags_fn_t push)856 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
857 {
858 	struct ndr_push *ndr;
859 	NTSTATUS status;
860 	size_t ret;
861 
862 	/* avoid recursion */
863 	if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
864 
865 	ndr = ndr_push_init_ctx(NULL);
866 	if (!ndr) return 0;
867 	ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
868 	ndr_push_set_switch_value(ndr, p, level);
869 	status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
870 	if (!NT_STATUS_IS_OK(status)) {
871 		return 0;
872 	}
873 	ret = ndr->offset;
874 	talloc_free(ndr);
875 	return ret;
876 }
877 
878 /*
879   get the current base for relative pointers for the push
880 */
ndr_push_get_relative_base_offset(struct ndr_push * ndr)881 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
882 {
883 	return ndr->relative_base_offset;
884 }
885 
886 /*
887   restore the old base for relative pointers for the push
888 */
ndr_push_restore_relative_base_offset(struct ndr_push * ndr,uint32_t offset)889 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
890 {
891 	ndr->relative_base_offset = offset;
892 }
893 
894 /*
895   setup the current base for relative pointers for the push
896   called in the NDR_SCALAR stage
897 */
ndr_push_setup_relative_base_offset1(struct ndr_push * ndr,const void * p,uint32_t offset)898 _PUBLIC_ NTSTATUS ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
899 {
900 	ndr->relative_base_offset = offset;
901 	return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
902 }
903 
904 /*
905   setup the current base for relative pointers for the push
906   called in the NDR_BUFFERS stage
907 */
ndr_push_setup_relative_base_offset2(struct ndr_push * ndr,const void * p)908 _PUBLIC_ NTSTATUS ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
909 {
910 	return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
911 }
912 
913 /*
914   push a relative object - stage1
915   this is called during SCALARS processing
916 */
ndr_push_relative_ptr1(struct ndr_push * ndr,const void * p)917 _PUBLIC_ NTSTATUS ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
918 {
919 	if (p == NULL) {
920 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
921 		return NT_STATUS_OK;
922 	}
923 	NDR_CHECK(ndr_push_align(ndr, 4));
924 	NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
925 	return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
926 }
927 
928 /*
929   push a relative object - stage2
930   this is called during buffers processing
931 */
ndr_push_relative_ptr2(struct ndr_push * ndr,const void * p)932 _PUBLIC_ NTSTATUS ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
933 {
934 	struct ndr_push_save save;
935 	uint32_t ptr_offset = 0xFFFFFFFF;
936 	if (p == NULL) {
937 		return NT_STATUS_OK;
938 	}
939 	ndr_push_save(ndr, &save);
940 	NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
941 	if (ptr_offset > ndr->offset) {
942 		return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
943 				      "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
944 				      ptr_offset, ndr->offset);
945 	}
946 	ndr->offset = ptr_offset;
947 	if (save.offset < ndr->relative_base_offset) {
948 		return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
949 				      "ndr_push_relative_ptr2 save.offset(%u) < ndr->relative_base_offset(%u)",
950 				      save.offset, ndr->relative_base_offset);
951 	}
952 	NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save.offset - ndr->relative_base_offset));
953 	ndr_push_restore(ndr, &save);
954 	return NT_STATUS_OK;
955 }
956 
957 /*
958   get the current base for relative pointers for the pull
959 */
ndr_pull_get_relative_base_offset(struct ndr_pull * ndr)960 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
961 {
962 	return ndr->relative_base_offset;
963 }
964 
965 /*
966   restore the old base for relative pointers for the pull
967 */
ndr_pull_restore_relative_base_offset(struct ndr_pull * ndr,uint32_t offset)968 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
969 {
970 	ndr->relative_base_offset = offset;
971 }
972 
973 /*
974   setup the current base for relative pointers for the pull
975   called in the NDR_SCALAR stage
976 */
ndr_pull_setup_relative_base_offset1(struct ndr_pull * ndr,const void * p,uint32_t offset)977 _PUBLIC_ NTSTATUS ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
978 {
979 	ndr->relative_base_offset = offset;
980 	return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
981 }
982 
983 /*
984   setup the current base for relative pointers for the pull
985   called in the NDR_BUFFERS stage
986 */
ndr_pull_setup_relative_base_offset2(struct ndr_pull * ndr,const void * p)987 _PUBLIC_ NTSTATUS ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
988 {
989 	return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
990 }
991 
992 /*
993   pull a relative object - stage1
994   called during SCALARS processing
995 */
ndr_pull_relative_ptr1(struct ndr_pull * ndr,const void * p,uint32_t rel_offset)996 _PUBLIC_ NTSTATUS ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
997 {
998 	return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
999 }
1000 
1001 /*
1002   pull a relative object - stage2
1003   called during BUFFERS processing
1004 */
ndr_pull_relative_ptr2(struct ndr_pull * ndr,const void * p)1005 _PUBLIC_ NTSTATUS ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1006 {
1007 	uint32_t rel_offset;
1008 	NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1009 	rel_offset += ndr->relative_base_offset;
1010 	if (rel_offset > ndr->data_size) {
1011 		return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1012 				      "ndr_pull_relative_ptr2 rel_offset(%u) > ndr->data_size(%u)",
1013 				      rel_offset, ndr->data_size);
1014 	}
1015 	return ndr_pull_set_offset(ndr, rel_offset);
1016 }
1017