r1239: move the old msrpc_<gen|parse>() functions to ndr_<push|pull>_format_blob()
[gd/samba-autobuild/.git] / source / librpc / ndr / ndr_basic.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    routines for marshalling/unmarshalling basic types
5
6    Copyright (C) Andrew Tridgell 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 #define NDR_BE(ndr) (((ndr)->flags & (LIBNDR_FLAG_BIGENDIAN|LIBNDR_FLAG_LITTLE_ENDIAN)) == LIBNDR_FLAG_BIGENDIAN)
26 #define NDR_SVAL(ndr, ofs) (NDR_BE(ndr)?RSVAL(ndr->data,ofs):SVAL(ndr->data,ofs))
27 #define NDR_IVAL(ndr, ofs) (NDR_BE(ndr)?RIVAL(ndr->data,ofs):IVAL(ndr->data,ofs))
28 #define NDR_SSVAL(ndr, ofs, v) do { if (NDR_BE(ndr))  { RSSVAL(ndr->data,ofs,v); } else SSVAL(ndr->data,ofs,v); } while (0)
29 #define NDR_SIVAL(ndr, ofs, v) do { if (NDR_BE(ndr))  { RSIVAL(ndr->data,ofs,v); } else SIVAL(ndr->data,ofs,v); } while (0)
30
31 /*
32   parse a uint8
33 */
34 NTSTATUS ndr_pull_uint8(struct ndr_pull *ndr, uint8_t *v)
35 {
36         NDR_PULL_NEED_BYTES(ndr, 1);
37         *v = CVAL(ndr->data, ndr->offset);
38         ndr->offset += 1;
39         return NT_STATUS_OK;
40 }
41
42
43 /*
44   parse a uint16
45 */
46 NTSTATUS ndr_pull_uint16(struct ndr_pull *ndr, uint16_t *v)
47 {
48         NDR_PULL_ALIGN(ndr, 2);
49         NDR_PULL_NEED_BYTES(ndr, 2);
50         *v = NDR_SVAL(ndr, ndr->offset);
51         ndr->offset += 2;
52         return NT_STATUS_OK;
53 }
54
55
56 /*
57   parse a uint32_t
58 */
59 NTSTATUS ndr_pull_uint32(struct ndr_pull *ndr, uint32_t *v)
60 {
61         NDR_PULL_ALIGN(ndr, 4);
62         NDR_PULL_NEED_BYTES(ndr, 4);
63         *v = NDR_IVAL(ndr, ndr->offset);
64         ndr->offset += 4;
65         return NT_STATUS_OK;
66 }
67
68 /*
69   parse a pointer
70 */
71 NTSTATUS ndr_pull_ptr(struct ndr_pull *ndr, uint32_t *v)
72 {
73         NTSTATUS status;
74         status = ndr_pull_uint32(ndr, v);
75         return status;
76 }
77
78 /*
79   parse a uint64
80 */
81 NTSTATUS ndr_pull_uint64(struct ndr_pull *ndr, uint64_t *v)
82 {
83         NDR_PULL_ALIGN(ndr, 4);
84         NDR_PULL_NEED_BYTES(ndr, 8);
85         *v = NDR_IVAL(ndr, ndr->offset);
86         *v |= (uint64_t)(NDR_IVAL(ndr, ndr->offset+4)) << 32;
87         ndr->offset += 8;
88         return NT_STATUS_OK;
89 }
90
91 /*
92   parse a int64
93 */
94 NTSTATUS ndr_pull_int64(struct ndr_pull *ndr, int64_t *v)
95 {
96         return ndr_pull_uint64(ndr, (uint64_t *)v);
97 }
98
99 /*
100   parse a HYPER_T
101 */
102 NTSTATUS ndr_pull_HYPER_T(struct ndr_pull *ndr, HYPER_T *v)
103 {
104         NDR_PULL_ALIGN(ndr, 8);
105         return ndr_pull_uint64(ndr, v);
106 }
107
108 /*
109   pull a NTSTATUS
110 */
111 NTSTATUS ndr_pull_NTSTATUS(struct ndr_pull *ndr, NTSTATUS *status)
112 {
113         uint32_t v;
114         NDR_CHECK(ndr_pull_uint32(ndr, &v));
115         *status = NT_STATUS(v);
116         return NT_STATUS_OK;
117 }
118
119 /*
120   push a NTSTATUS
121 */
122 NTSTATUS ndr_push_NTSTATUS(struct ndr_push *ndr, NTSTATUS status)
123 {
124         return ndr_push_uint32(ndr, NT_STATUS_V(status));
125 }
126
127 void ndr_print_NTSTATUS(struct ndr_print *ndr, const char *name, NTSTATUS *r)
128 {
129         ndr->print(ndr, "%-25s: %s", name, nt_errstr(*r));
130 }
131
132 /*
133   pull a WERROR
134 */
135 NTSTATUS ndr_pull_WERROR(struct ndr_pull *ndr, WERROR *status)
136 {
137         uint32_t v;
138         NDR_CHECK(ndr_pull_uint32(ndr, &v));
139         *status = W_ERROR(v);
140         return NT_STATUS_OK;
141 }
142
143 /*
144   push a WERROR
145 */
146 NTSTATUS ndr_push_WERROR(struct ndr_push *ndr, WERROR status)
147 {
148         return ndr_push_uint32(ndr, W_ERROR_V(status));
149 }
150
151 void ndr_print_WERROR(struct ndr_print *ndr, const char *name, WERROR *r)
152 {
153         ndr->print(ndr, "%-25s: %s", name, win_errstr(*r));
154 }
155
156 /*
157   parse a set of bytes
158 */
159 NTSTATUS ndr_pull_bytes(struct ndr_pull *ndr, char *data, uint32_t n)
160 {
161         NDR_PULL_NEED_BYTES(ndr, n);
162         memcpy(data, ndr->data + ndr->offset, n);
163         ndr->offset += n;
164         return NT_STATUS_OK;
165 }
166
167 /*
168   pull an array of uint8
169 */
170 NTSTATUS ndr_pull_array_uint8(struct ndr_pull *ndr, int ndr_flags, char *data, uint32_t n)
171 {
172         if (!(ndr_flags & NDR_SCALARS)) {
173                 return NT_STATUS_OK;
174         }
175         return ndr_pull_bytes(ndr, data, n);
176 }
177
178
179 /*
180   pull an array of uint16
181 */
182 NTSTATUS ndr_pull_array_uint16(struct ndr_pull *ndr, int ndr_flags, uint16_t *data, uint32_t n)
183 {
184         uint32_t i;
185         if (!(ndr_flags & NDR_SCALARS)) {
186                 return NT_STATUS_OK;
187         }
188         for (i=0;i<n;i++) {
189                 NDR_CHECK(ndr_pull_uint16(ndr, &data[i]));
190         }
191         return NT_STATUS_OK;
192 }
193
194 /*
195   pull a const array of uint32_t
196 */
197 NTSTATUS ndr_pull_array_uint32(struct ndr_pull *ndr, int ndr_flags, uint32_t *data, uint32_t n)
198 {
199         uint32_t i;
200         if (!(ndr_flags & NDR_SCALARS)) {
201                 return NT_STATUS_OK;
202         }
203         for (i=0;i<n;i++) {
204                 NDR_CHECK(ndr_pull_uint32(ndr, &data[i]));
205         }
206         return NT_STATUS_OK;
207 }
208
209 /*
210   push a uint8
211 */
212 NTSTATUS ndr_push_uint8(struct ndr_push *ndr, uint8_t v)
213 {
214         NDR_PUSH_NEED_BYTES(ndr, 1);
215         SCVAL(ndr->data, ndr->offset, v);
216         ndr->offset += 1;
217         return NT_STATUS_OK;
218 }
219
220 /*
221   push a uint16
222 */
223 NTSTATUS ndr_push_uint16(struct ndr_push *ndr, uint16_t v)
224 {
225         NDR_PUSH_ALIGN(ndr, 2);
226         NDR_PUSH_NEED_BYTES(ndr, 2);
227         NDR_SSVAL(ndr, ndr->offset, v);
228         ndr->offset += 2;
229         return NT_STATUS_OK;
230 }
231
232 /*
233   push a uint32_t
234 */
235 NTSTATUS ndr_push_uint32(struct ndr_push *ndr, uint32_t v)
236 {
237         NDR_PUSH_ALIGN(ndr, 4);
238         NDR_PUSH_NEED_BYTES(ndr, 4);
239         NDR_SIVAL(ndr, ndr->offset, v);
240         ndr->offset += 4;
241         return NT_STATUS_OK;
242 }
243
244 /*
245   push a uint64
246 */
247 NTSTATUS ndr_push_uint64(struct ndr_push *ndr, uint64_t v)
248 {
249         NDR_PUSH_ALIGN(ndr, 4);
250         NDR_PUSH_NEED_BYTES(ndr, 8);
251         NDR_SIVAL(ndr, ndr->offset, (v & 0xFFFFFFFF));
252         NDR_SIVAL(ndr, ndr->offset+4, (v>>32));
253         ndr->offset += 8;
254         return NT_STATUS_OK;
255 }
256
257 /*
258   push a int64
259 */
260 NTSTATUS ndr_push_int64(struct ndr_push *ndr, int64_t v)
261 {
262         return ndr_push_uint64(ndr, (uint64_t)v);
263 }
264
265 /*
266   push a HYPER_T
267 */
268 NTSTATUS ndr_push_HYPER_T(struct ndr_push *ndr, HYPER_T v)
269 {
270         NDR_PUSH_ALIGN(ndr, 8);
271         return ndr_push_uint64(ndr, v);
272 }
273
274 NTSTATUS ndr_push_align(struct ndr_push *ndr, size_t size)
275 {
276         NDR_PUSH_ALIGN(ndr, size);
277         return NT_STATUS_OK;
278 }
279
280 NTSTATUS ndr_pull_align(struct ndr_pull *ndr, size_t size)
281 {
282         NDR_PULL_ALIGN(ndr, size);
283         return NT_STATUS_OK;
284 }
285
286 /*
287   push some bytes
288 */
289 NTSTATUS ndr_push_bytes(struct ndr_push *ndr, const char *data, uint32_t n)
290 {
291         NDR_PUSH_NEED_BYTES(ndr, n);
292         memcpy(ndr->data + ndr->offset, data, n);
293         ndr->offset += n;
294         return NT_STATUS_OK;
295 }
296
297 /*
298   push some zero bytes
299 */
300 NTSTATUS ndr_push_zero(struct ndr_push *ndr, uint32_t n)
301 {
302         NDR_PUSH_NEED_BYTES(ndr, n);
303         memset(ndr->data + ndr->offset, 0, n);
304         ndr->offset += n;
305         return NT_STATUS_OK;
306 }
307
308 /*
309   push an array of uint8
310 */
311 NTSTATUS ndr_push_array_uint8(struct ndr_push *ndr, int ndr_flags, const char *data, uint32_t n)
312 {
313         if (!(ndr_flags & NDR_SCALARS)) {
314                 return NT_STATUS_OK;
315         }
316         return ndr_push_bytes(ndr, data, n);
317 }
318
319 /*
320   push an array of uint16
321 */
322 NTSTATUS ndr_push_array_uint16(struct ndr_push *ndr, int ndr_flags, const uint16_t *data, uint32_t n)
323 {
324         int i;
325         if (!(ndr_flags & NDR_SCALARS)) {
326                 return NT_STATUS_OK;
327         }
328         for (i=0;i<n;i++) {
329                 NDR_CHECK(ndr_push_uint16(ndr, data[i]));
330         }
331         return NT_STATUS_OK;
332 }
333
334 /*
335   push an array of uint32_t
336 */
337 NTSTATUS ndr_push_array_uint32(struct ndr_push *ndr, int ndr_flags, const uint32_t *data, uint32_t n)
338 {
339         int i;
340         if (!(ndr_flags & NDR_SCALARS)) {
341                 return NT_STATUS_OK;
342         }
343         for (i=0;i<n;i++) {
344                 NDR_CHECK(ndr_push_uint32(ndr, data[i]));
345         }
346         return NT_STATUS_OK;
347 }
348
349 /*
350   save the current position
351  */
352 void ndr_push_save(struct ndr_push *ndr, struct ndr_push_save *save)
353 {
354         save->offset = ndr->offset;
355 }
356
357 /*
358   restore the position
359  */
360 void ndr_push_restore(struct ndr_push *ndr, struct ndr_push_save *save)
361 {
362         ndr->offset = save->offset;
363 }
364
365 /*
366   push a 1 if a pointer is non-NULL, otherwise 0
367 */
368 NTSTATUS ndr_push_ptr(struct ndr_push *ndr, const void *p)
369 {
370         uint32_t ptr = 0;
371         if (p) {
372                 /* we do this to ensure that we generate unique ref ids,
373                    which means we can handle the case where a MS programmer
374                    forgot to mark a pointer as unique */
375                 ndr->ptr_count++;
376                 ptr = ndr->ptr_count;
377         }
378         return ndr_push_uint32(ndr, ptr);
379 }
380
381
382 /*
383   pull a general string from the wire
384 */
385 NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
386 {
387         char *as=NULL;
388         uint32_t len1, ofs, len2;
389         uint16_t len3;
390         int ret;
391         int chset = CH_UCS2;
392
393         if (!(ndr_flags & NDR_SCALARS)) {
394                 return NT_STATUS_OK;
395         }
396
397         if (NDR_BE(ndr)) {
398                 chset = CH_UCS2BE;
399         }
400
401         switch (ndr->flags & LIBNDR_STRING_FLAGS) {
402         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
403         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
404                 NDR_CHECK(ndr_pull_uint32(ndr, &len1));
405                 NDR_CHECK(ndr_pull_uint32(ndr, &ofs));
406                 NDR_CHECK(ndr_pull_uint32(ndr, &len2));
407                 if (len2 > len1) {
408                         return ndr_pull_error(ndr, NDR_ERR_STRING, 
409                                               "Bad string lengths len1=%u ofs=%u len2=%u\n", 
410                                               len1, ofs, len2);
411                 }
412                 if (len2 == 0) {
413                         *s = talloc_strdup(ndr->mem_ctx, "");
414                         break;
415                 }
416                 NDR_PULL_NEED_BYTES(ndr, len2*2);
417                 ret = convert_string_talloc(ndr->mem_ctx, chset, CH_UNIX, 
418                                             ndr->data+ndr->offset, 
419                                             len2*2,
420                                             (const void **)&as);
421                 if (ret == -1) {
422                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
423                                               "Bad character conversion");
424                 }
425                 NDR_CHECK(ndr_pull_advance(ndr, len2*2));
426
427                 /* this is a way of detecting if a string is sent with the wrong
428                    termination */
429                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
430                         if (strlen(as) < len2) {
431                                 DEBUG(6,("short string '%s'\n", as));
432                         }
433                 } else {
434                         if (strlen(as) == len2) {
435                                 DEBUG(6,("long string '%s'\n", as));
436                         }
437                 }
438                 *s = as;
439                 break;
440
441         case LIBNDR_FLAG_STR_SIZE4:
442                 NDR_CHECK(ndr_pull_uint32(ndr, &len1));
443                 NDR_PULL_NEED_BYTES(ndr, len1*2);
444                 if (len1 == 0) {
445                         *s = talloc_strdup(ndr->mem_ctx, "");
446                         break;
447                 }
448                 ret = convert_string_talloc(ndr->mem_ctx, chset, CH_UNIX, 
449                                             ndr->data+ndr->offset, 
450                                             len1*2,
451                                             (const void **)&as);
452                 if (ret == -1) {
453                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
454                                               "Bad character conversion");
455                 }
456                 NDR_CHECK(ndr_pull_advance(ndr, len1*2));
457                 *s = as;
458                 break;
459
460         case LIBNDR_FLAG_STR_NULLTERM:
461                 len1 = strnlen_w(ndr->data+ndr->offset, 
462                                  (ndr->data_size - ndr->offset)/2);
463                 if (len1*2+2 <= ndr->data_size - ndr->offset) {
464                         len1++;
465                 }
466                 ret = convert_string_talloc(ndr->mem_ctx, chset, CH_UNIX, 
467                                             ndr->data+ndr->offset, 
468                                             len1*2,
469                                             (const void **)s);
470                 if (ret == -1) {
471                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
472                                               "Bad character conversion");
473                 }
474                 NDR_CHECK(ndr_pull_advance(ndr, len1*2));
475                 break;
476
477         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
478         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
479                 NDR_CHECK(ndr_pull_uint32(ndr, &len1));
480                 NDR_CHECK(ndr_pull_uint32(ndr, &ofs));
481                 NDR_CHECK(ndr_pull_uint32(ndr, &len2));
482                 if (len2 > len1) {
483                         return ndr_pull_error(ndr, NDR_ERR_STRING, 
484                                               "Bad ascii string lengths len1=%u ofs=%u len2=%u\n", 
485                                               len1, ofs, len2);
486                 }
487                 NDR_ALLOC_N(ndr, as, (len2+1));
488                 NDR_CHECK(ndr_pull_bytes(ndr, as, len2));
489                 as[len2] = 0;
490                 (*s) = as;
491                 break;
492
493         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4:
494                 NDR_CHECK(ndr_pull_uint32(ndr, &ofs));
495                 NDR_CHECK(ndr_pull_uint32(ndr, &len2));
496                 NDR_ALLOC_N(ndr, as, (len2+1));
497                 NDR_CHECK(ndr_pull_bytes(ndr, as, len2));
498                 as[len2] = 0;
499                 (*s) = as;
500                 break;
501
502         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_SIZE2:
503                 NDR_CHECK(ndr_pull_uint16(ndr, &len3));
504                 NDR_ALLOC_N(ndr, as, (len3+1));
505                 NDR_CHECK(ndr_pull_bytes(ndr, as, len3));
506                 as[len3] = 0;
507                 (*s) = as;
508                 break;
509
510         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM:
511                 len1 = strnlen(ndr->data+ndr->offset, (ndr->data_size - ndr->offset));
512                 if (len1+1 <= ndr->data_size - ndr->offset) {
513                         len1++;
514                 }
515                 NDR_ALLOC_N(ndr, as, (len1+1));
516                 NDR_CHECK(ndr_pull_bytes(ndr, as, len1));
517                 as[len1] = 0;
518                 (*s) = as;
519                 break;
520
521         default:
522                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
523                                       ndr->flags & LIBNDR_STRING_FLAGS);
524         }
525
526         return NT_STATUS_OK;
527 }
528
529
530 /*
531   push a general string onto the wire
532 */
533 NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
534 {
535         ssize_t s_len, c_len;
536         int ret;
537         int chset = CH_UCS2;
538
539         if (!(ndr_flags & NDR_SCALARS)) {
540                 return NT_STATUS_OK;
541         }
542
543         if (NDR_BE(ndr)) {
544                 chset = CH_UCS2BE;
545         }
546         
547         s_len = s?strlen(s):0;
548         c_len = s?strlen_m(s):0;
549
550         switch (ndr->flags & LIBNDR_STRING_FLAGS) {
551         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
552                 NDR_CHECK(ndr_push_uint32(ndr, c_len+1));
553                 NDR_CHECK(ndr_push_uint32(ndr, 0));
554                 NDR_CHECK(ndr_push_uint32(ndr, c_len+1));
555                 NDR_PUSH_NEED_BYTES(ndr, c_len*2 + 2);
556                 ret = convert_string(CH_UNIX, chset, 
557                                      s, s_len+1,
558                                      ndr->data+ndr->offset, c_len*2 + 2);
559                 if (ret == -1) {
560                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
561                                               "Bad character conversion");
562                 }
563                 ndr->offset += c_len*2 + 2;
564                 break;
565
566         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
567                 NDR_CHECK(ndr_push_uint32(ndr, c_len));
568                 NDR_CHECK(ndr_push_uint32(ndr, 0));
569                 NDR_CHECK(ndr_push_uint32(ndr, c_len));
570                 NDR_PUSH_NEED_BYTES(ndr, c_len*2);
571                 ret = convert_string(CH_UNIX, chset, 
572                                      s, s_len,
573                                      ndr->data+ndr->offset, c_len*2);
574                 if (ret == -1) {
575                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
576                                               "Bad character conversion");
577                 }
578                 ndr->offset += c_len*2;
579                 break;
580
581         case LIBNDR_FLAG_STR_SIZE4:
582                 NDR_CHECK(ndr_push_uint32(ndr, c_len + 1));
583                 NDR_PUSH_NEED_BYTES(ndr, c_len*2 + 2);
584                 ret = convert_string(CH_UNIX, chset, 
585                                      s, s_len + 1,
586                                      ndr->data+ndr->offset, c_len*2 + 2);
587                 if (ret == -1) {
588                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
589                                               "Bad character conversion");
590                 }
591                 ndr->offset += c_len*2 + 2;
592                 break;
593
594         case LIBNDR_FLAG_STR_NULLTERM:
595                 NDR_PUSH_NEED_BYTES(ndr, c_len*2 + 2);
596                 ret = convert_string(CH_UNIX, chset, 
597                                      s, s_len+1,
598                                      ndr->data+ndr->offset, c_len*2 + 2);
599                 if (ret == -1) {
600                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
601                                               "Bad character conversion");
602                 }
603                 ndr->offset += c_len*2 + 2;
604                 break;
605                 
606         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
607                 NDR_CHECK(ndr_push_uint32(ndr, c_len+1));
608                 NDR_CHECK(ndr_push_uint32(ndr, 0));
609                 NDR_CHECK(ndr_push_uint32(ndr, c_len+1));
610                 NDR_PUSH_NEED_BYTES(ndr, c_len + 1);
611                 ret = convert_string(CH_UNIX, CH_DOS, 
612                                      s, s_len + 1,
613                                      ndr->data+ndr->offset, c_len + 1);
614                 if (ret == -1) {
615                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
616                                               "Bad character conversion");
617                 }
618                 ndr->offset += c_len + 1;
619                 break;
620
621         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
622                 NDR_CHECK(ndr_push_uint32(ndr, c_len));
623                 NDR_CHECK(ndr_push_uint32(ndr, 0));
624                 NDR_CHECK(ndr_push_uint32(ndr, c_len));
625                 NDR_PUSH_NEED_BYTES(ndr, c_len);
626                 ret = convert_string(CH_UNIX, CH_DOS, 
627                                      s, s_len,
628                                      ndr->data+ndr->offset, c_len);
629                 if (ret == -1) {
630                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
631                                               "Bad character conversion");
632                 }
633                 ndr->offset += c_len;
634                 break;
635
636         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_LEN4:
637                 NDR_CHECK(ndr_push_uint32(ndr, 0));
638                 NDR_CHECK(ndr_push_uint32(ndr, c_len+1));
639                 NDR_PUSH_NEED_BYTES(ndr, c_len + 1);
640                 ret = convert_string(CH_UNIX, CH_DOS, 
641                                      s, s_len + 1,
642                                      ndr->data+ndr->offset, c_len + 1);
643                 if (ret == -1) {
644                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
645                                               "Bad character conversion");
646                 }
647                 ndr->offset += c_len + 1;
648                 break;
649
650         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_SIZE2:
651                 NDR_CHECK(ndr_push_uint16(ndr, c_len+1));
652                 NDR_PUSH_NEED_BYTES(ndr, c_len + 1);
653                 ret = convert_string(CH_UNIX, CH_DOS, 
654                                      s, s_len + 1,
655                                      ndr->data+ndr->offset, c_len + 1);
656                 if (ret == -1) {
657                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
658                                               "Bad character conversion");
659                 }
660                 ndr->offset += c_len + 1;
661                 break;
662
663         case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM:
664                 NDR_PUSH_NEED_BYTES(ndr, c_len + 1);
665                 ret = convert_string(CH_UNIX, CH_DOS, 
666                                      s, s_len+1,
667                                      ndr->data+ndr->offset, c_len + 1);
668                 if (ret == -1) {
669                         return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
670                                               "Bad character conversion");
671                 }
672                 ndr->offset += c_len + 1;
673                 break;
674
675         default:
676                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
677                                       ndr->flags & LIBNDR_STRING_FLAGS);
678         }
679
680         return NT_STATUS_OK;
681 }
682
683 /*
684   push a NTTIME
685 */
686 NTSTATUS ndr_push_NTTIME(struct ndr_push *ndr, NTTIME t)
687 {
688         NDR_CHECK(ndr_push_uint64(ndr, t));
689         return NT_STATUS_OK;
690 }
691
692 /*
693   pull a NTTIME
694 */
695 NTSTATUS ndr_pull_NTTIME(struct ndr_pull *ndr, NTTIME *t)
696 {
697         NDR_CHECK(ndr_pull_uint64(ndr, t));
698         return NT_STATUS_OK;
699 }
700
701 /*
702   push a time_t
703 */
704 NTSTATUS ndr_push_time_t(struct ndr_push *ndr, time_t t)
705 {
706         return ndr_push_uint32(ndr, t);
707 }
708
709 /*
710   pull a time_t
711 */
712 NTSTATUS ndr_pull_time_t(struct ndr_pull *ndr, time_t *t)
713 {
714         uint32_t tt;
715         NDR_CHECK(ndr_pull_uint32(ndr, &tt));
716         *t = tt;
717         return NT_STATUS_OK;
718 }
719
720
721 void ndr_print_struct(struct ndr_print *ndr, const char *name, const char *type)
722 {
723         ndr->print(ndr, "%s: struct %s", name, type);
724 }
725
726 void ndr_print_uint8(struct ndr_print *ndr, const char *name, uint8_t v)
727 {
728         ndr->print(ndr, "%-25s: 0x%02x (%u)", name, v, v);
729 }
730
731 void ndr_print_uint16(struct ndr_print *ndr, const char *name, uint16_t v)
732 {
733         ndr->print(ndr, "%-25s: 0x%04x (%u)", name, v, v);
734 }
735
736 void ndr_print_uint32(struct ndr_print *ndr, const char *name, uint32_t v)
737 {
738         ndr->print(ndr, "%-25s: 0x%08x (%u)", name, v, v);
739 }
740
741 void ndr_print_uint64(struct ndr_print *ndr, const char *name, uint64_t v)
742 {
743         ndr->print(ndr, "%-25s: 0x%08x%08x", name, (uint32_t)(v >> 32), (uint32_t)(v & 0xFFFFFFFF));
744 }
745
746 void ndr_print_int64(struct ndr_print *ndr, const char *name, int64_t v)
747 {
748         ndr->print(ndr, "%-25s: 0x%08x%08x (%lld)", name, 
749                    (uint32_t)(v >> 32), 
750                    (uint32_t)(v & 0xFFFFFFFF),
751                    v);
752 }
753
754 void ndr_print_HYPER_T(struct ndr_print *ndr, const char *name, HYPER_T v)
755 {
756         ndr->print(ndr, "%-25s: 0x%08x%08x", name, (uint32_t)(v >> 32), (uint32_t)(v & 0xFFFFFFFF));
757 }
758
759 void ndr_print_ptr(struct ndr_print *ndr, const char *name, const void *p)
760 {
761         if (p) {
762                 ndr->print(ndr, "%-25s: *", name);
763         } else {
764                 ndr->print(ndr, "%-25s: NULL", name);
765         }
766 }
767
768 void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
769 {
770         if (s) {
771                 ndr->print(ndr, "%-25s: '%s'", name, s);
772         } else {
773                 ndr->print(ndr, "%-25s: NULL", name);
774         }
775 }
776
777 void ndr_print_NTTIME(struct ndr_print *ndr, const char *name, NTTIME t)
778 {
779         ndr->print(ndr, "%-25s: %s", name, nt_time_string(ndr->mem_ctx, t));
780 }
781
782 void ndr_print_time_t(struct ndr_print *ndr, const char *name, time_t t)
783 {
784         if (t == (time_t)-1 || t == 0) {
785                 ndr->print(ndr, "%-25s: (time_t)%d", name, (int)t);
786         } else {
787                 ndr->print(ndr, "%-25s: %s", name, timestring(ndr->mem_ctx, t));
788         }
789 }
790
791 void ndr_print_union(struct ndr_print *ndr, const char *name, uint16_t level, const char *type)
792 {
793         ndr->print(ndr, "%-25s: union %s(case %u)", name, type, level);
794 }
795
796 void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint16_t level)
797 {
798         ndr->print(ndr, "UNKNOWN LEVEL %u", level);
799 }
800
801 void ndr_print_array_uint32(struct ndr_print *ndr, const char *name, 
802                             const uint32_t *data, uint32_t count)
803 {
804         int i;
805
806         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
807         ndr->depth++;
808         for (i=0;i<count;i++) {
809                 char *idx=NULL;
810                 asprintf(&idx, "[%d]", i);
811                 if (idx) {
812                         ndr_print_uint32(ndr, idx, data[i]);
813                         free(idx);
814                 }
815         }
816         ndr->depth--;   
817 }
818
819 void ndr_print_array_uint16(struct ndr_print *ndr, const char *name, 
820                             const uint16_t *data, uint32_t count)
821 {
822         int i;
823
824         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
825         ndr->depth++;
826         for (i=0;i<count;i++) {
827                 char *idx=NULL;
828                 asprintf(&idx, "[%d]", i);
829                 if (idx) {
830                         ndr_print_uint16(ndr, idx, data[i]);
831                         free(idx);
832                 }
833         }
834         ndr->depth--;   
835 }
836
837 void ndr_print_array_uint8(struct ndr_print *ndr, const char *name, 
838                            const uint8_t *data, uint32_t count)
839 {
840         int i;
841
842         if (count <= 600 && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) {
843                 char s[1202];
844                 for (i=0;i<count;i++) {
845                         snprintf(&s[i*2], 3, "%02x", data[i]);
846                 }
847                 s[i*2] = 0;
848                 ndr->print(ndr, "%-25s: %s", name, s);
849                 return;
850         }
851
852         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
853         ndr->depth++;
854         for (i=0;i<count;i++) {
855                 char *idx=NULL;
856                 asprintf(&idx, "[%d]", i);
857                 if (idx) {
858                         ndr_print_uint8(ndr, idx, data[i]);
859                         free(idx);
860                 }
861         }
862         ndr->depth--;   
863 }
864
865 /*
866   build a GUID from a string
867 */
868 NTSTATUS GUID_from_string(const char *s, struct GUID *guid)
869 {
870         uint32_t time_low;
871         uint32_t time_mid, time_hi_and_version;
872         uint32_t clock_seq[2];
873         uint32_t node[6];
874         int i;
875
876         if (11 != sscanf(s, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
877                          &time_low, &time_mid, &time_hi_and_version, 
878                          &clock_seq[0], &clock_seq[1],
879                          &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) {
880                 return NT_STATUS_INVALID_PARAMETER;
881         }
882
883         guid->time_low = time_low;
884         guid->time_mid = time_mid;
885         guid->time_hi_and_version = time_hi_and_version;
886         guid->clock_seq[0] = clock_seq[0];
887         guid->clock_seq[1] = clock_seq[1];
888         for (i=0;i<6;i++) {
889                 guid->node[i] = node[i];
890         }
891
892         return NT_STATUS_OK;
893 }
894
895 /*
896   its useful to be able to display these in debugging messages
897 */
898 const char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid)
899 {
900         return talloc_asprintf(mem_ctx, 
901                                "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
902                                guid->time_low, guid->time_mid,
903                                guid->time_hi_and_version,
904                                guid->clock_seq[0],
905                                guid->clock_seq[1],
906                                guid->node[0], guid->node[1],
907                                guid->node[2], guid->node[3],
908                                guid->node[4], guid->node[5]);
909 }
910
911 void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid)
912 {
913         ndr->print(ndr, "%-25s: %s", name, GUID_string(ndr->mem_ctx, guid));
914 }
915
916 void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r)
917 {
918         ndr->print(ndr, "%-25s: DATA_BLOB length=%u", name, r.length);
919         if (r.length) {
920                 dump_data(10, r.data, r.length);
921         }
922 }
923
924
925 /*
926   push a DATA_BLOB onto the wire. 
927 */
928 NTSTATUS ndr_push_DATA_BLOB(struct ndr_push *ndr, DATA_BLOB blob)
929 {
930         if (ndr->flags & LIBNDR_ALIGN_FLAGS) {
931                 if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
932                         blob.length = NDR_ALIGN(ndr, 2);
933                 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
934                         blob.length = NDR_ALIGN(ndr, 4);
935                 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
936                         blob.length = NDR_ALIGN(ndr, 8);
937                 }
938                 NDR_PUSH_ALLOC_SIZE(ndr, blob.data, blob.length);
939                 data_blob_clear(&blob);
940         } else if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
941                 NDR_CHECK(ndr_push_uint32(ndr, blob.length));
942         }
943         NDR_CHECK(ndr_push_bytes(ndr, blob.data, blob.length));
944         return NT_STATUS_OK;
945 }
946
947 /*
948   pull a DATA_BLOB from the wire. 
949 */
950 NTSTATUS ndr_pull_DATA_BLOB(struct ndr_pull *ndr, DATA_BLOB *blob)
951 {
952         uint32_t length;
953
954         if (ndr->flags & LIBNDR_ALIGN_FLAGS) {
955                 if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
956                         length = NDR_ALIGN(ndr, 2);
957                 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
958                         length = NDR_ALIGN(ndr, 4);
959                 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
960                         length = NDR_ALIGN(ndr, 8);
961                 }
962                 if (ndr->data_size - ndr->offset < length) {
963                         length = ndr->data_size - ndr->offset;
964                 }
965         } else if (ndr->flags & LIBNDR_FLAG_REMAINING) {
966                 length = ndr->data_size - ndr->offset;
967         } else {
968                 NDR_CHECK(ndr_pull_uint32(ndr, &length));
969         }
970         NDR_PULL_NEED_BYTES(ndr, length);
971         *blob = data_blob_talloc(ndr->mem_ctx, ndr->data+ndr->offset, length);
972         ndr->offset += length;
973         return NT_STATUS_OK;
974 }
975
976 /*
977   this is a tiny ndr packet generator. This
978   generator is not general enough for all our rpc needs, its just
979   enough for the ntlmssp code
980
981   format specifiers are:
982
983   U = unicode string (input is unix string)
984   a = address (input is char *unix_string)
985       (1 byte type, 1 byte length, unicode/ASCII string, all inline)
986   A = ASCII string (input is unix string)
987   B = data blob (pointer + length)
988   b = data blob in header (pointer + length)
989   D
990   d = word (4 bytes)
991   C = constant ascii string
992  */
993 NTSTATUS ndr_push_format_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
994                const char *format, ...)
995 {
996         int i, n;
997         va_list ap;
998         char *s;
999         uint8_t *b;
1000         int head_size=0, data_size=0;
1001         int head_ofs, data_ofs;
1002
1003         /* first scan the format to work out the header and body size */
1004         va_start(ap, format);
1005         for (i=0; format[i]; i++) {
1006                 switch (format[i]) {
1007                 case 'U':
1008                         s = va_arg(ap, char *);
1009                         head_size += 8;
1010                         data_size += str_charnum(s) * 2;
1011                         break;
1012                 case 'A':
1013                         s = va_arg(ap, char *);
1014                         head_size += 8;
1015                         data_size += str_ascii_charnum(s);
1016                         break;
1017                 case 'a':
1018                         n = va_arg(ap, int);
1019                         s = va_arg(ap, char *);
1020                         data_size += (str_charnum(s) * 2) + 4;
1021                         break;
1022                 case 'B':
1023                         b = va_arg(ap, uint8_t *);
1024                         head_size += 8;
1025                         data_size += va_arg(ap, int);
1026                         break;
1027                 case 'b':
1028                         b = va_arg(ap, uint8_t *);
1029                         head_size += va_arg(ap, int);
1030                         break;
1031                 case 'd':
1032                         n = va_arg(ap, int);
1033                         head_size += 4;
1034                         break;
1035                 case 'C':
1036                         s = va_arg(ap, char *);
1037                         head_size += str_charnum(s) + 1;
1038                         break;
1039                 }
1040         }
1041         va_end(ap);
1042
1043         /* allocate the space, then scan the format again to fill in the values */
1044         *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
1045
1046         if (blob->length != (head_size + data_size)) {
1047                 return NT_STATUS_NO_MEMORY;
1048         }
1049
1050         head_ofs = 0;
1051         data_ofs = head_size;
1052
1053         va_start(ap, format);
1054         for (i=0; format[i]; i++) {
1055                 switch (format[i]) {
1056                 case 'U':
1057                         s = va_arg(ap, char *);
1058                         n = str_charnum(s);
1059                         SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
1060                         SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
1061                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
1062                         push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN);
1063                         data_ofs += n*2;
1064                         break;
1065                 case 'A':
1066                         s = va_arg(ap, char *);
1067                         n = str_ascii_charnum(s);
1068                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
1069                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
1070                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
1071                         push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN);
1072                         data_ofs += n;
1073                         break;
1074                 case 'a':
1075                         n = va_arg(ap, int);
1076                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
1077                         s = va_arg(ap, char *);
1078                         n = str_charnum(s);
1079                         SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
1080                         if (0 < n) {
1081                                 push_string(NULL, blob->data+data_ofs, s, n*2,
1082                                             STR_UNICODE|STR_NOALIGN);
1083                         }
1084                         data_ofs += n*2;
1085                         break;
1086
1087                 case 'B':
1088                         b = va_arg(ap, uint8_t *);
1089                         n = va_arg(ap, int);
1090                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
1091                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
1092                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
1093                         if (n && b) /* don't follow null pointers... */
1094                                 memcpy(blob->data+data_ofs, b, n);
1095                         data_ofs += n;
1096                         break;
1097                 case 'd':
1098                         n = va_arg(ap, int);
1099                         SIVAL(blob->data, head_ofs, n); head_ofs += 4;
1100                         break;
1101                 case 'b':
1102                         b = va_arg(ap, uint8_t *);
1103                         n = va_arg(ap, int);
1104                         memcpy(blob->data + head_ofs, b, n);
1105                         head_ofs += n;
1106                         break;
1107                 case 'C':
1108                         s = va_arg(ap, char *);
1109                         head_ofs += push_string(NULL, blob->data+head_ofs, s, -1, 
1110                                                 STR_ASCII|STR_TERMINATE);
1111                         break;
1112                 }
1113         }
1114         va_end(ap);
1115
1116         return NT_STATUS_OK;
1117 }
1118
1119
1120 /* a helpful macro to avoid running over the end of our blob */
1121 #define NEED_DATA(amount) \
1122 if ((head_ofs + amount) > blob->length) { \
1123         return NT_STATUS_INVALID_PARAMETER; \
1124 }
1125
1126 /*
1127   this is a tiny msrpc packet parser. This the the partner of msrpc_gen
1128
1129   format specifiers are:
1130
1131   U = unicode string (output is unix string)
1132   A = ascii string
1133   B = data blob
1134   b = data blob in header
1135   d = word (4 bytes)
1136   C = constant ascii string
1137  */
1138
1139 NTSTATUS ndr_pull_format_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1140                  const char *format, ...)
1141 {
1142         int i;
1143         va_list ap;
1144         const char **ps, *s;
1145         DATA_BLOB *b;
1146         size_t head_ofs = 0;
1147         uint16_t len1, len2;
1148         uint32_t ptr;
1149         uint32_t *v;
1150         pstring p;
1151
1152         va_start(ap, format);
1153         for (i=0; format[i]; i++) {
1154                 switch (format[i]) {
1155                 case 'U':
1156                         NEED_DATA(8);
1157                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
1158                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
1159                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
1160
1161                         ps = va_arg(ap, char **);
1162                         if (len1 == 0 && len2 == 0) {
1163                                 *ps = "";
1164                         } else {
1165                                 /* make sure its in the right format - be strict */
1166                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
1167                                         return NT_STATUS_INVALID_PARAMETER;
1168                                 }
1169                                 if (len1 & 1) {
1170                                         /* if odd length and unicode */
1171                                         return NT_STATUS_INVALID_PARAMETER;
1172                                 }
1173                                 if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data)
1174                                         return NT_STATUS_INVALID_PARAMETER;
1175
1176                                 if (0 < len1) {
1177                                         pull_string(NULL, p, blob->data + ptr, sizeof(p), 
1178                                                     len1, 
1179                                                     STR_UNICODE|STR_NOALIGN);
1180                                         (*ps) = talloc_strdup(mem_ctx, p);
1181                                         if (!(*ps)) {
1182                                                 return NT_STATUS_NO_MEMORY;
1183                                         }
1184                                 } else {
1185                                         (*ps) = "";
1186                                 }
1187                         }
1188                         break;
1189                 case 'A':
1190                         NEED_DATA(8);
1191                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
1192                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
1193                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
1194
1195                         ps = va_arg(ap, char **);
1196                         /* make sure its in the right format - be strict */
1197                         if (len1 == 0 && len2 == 0) {
1198                                 *ps = "";
1199                         } else {
1200                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
1201                                         return NT_STATUS_INVALID_PARAMETER;
1202                                 }
1203
1204                                 if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data)
1205                                         return NT_STATUS_INVALID_PARAMETER;     
1206
1207                                 if (0 < len1) {
1208                                         pull_string(NULL, p, blob->data + ptr, sizeof(p), 
1209                                                     len1, 
1210                                                     STR_ASCII|STR_NOALIGN);
1211                                         (*ps) = talloc_strdup(mem_ctx, p);
1212                                         if (!(*ps)) {
1213                                                 return NT_STATUS_NO_MEMORY;
1214                                         }
1215                                 } else {
1216                                         (*ps) = "";
1217                                 }
1218                         }
1219                         break;
1220                 case 'B':
1221                         NEED_DATA(8);
1222                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
1223                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
1224                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
1225
1226                         b = (DATA_BLOB *)va_arg(ap, void *);
1227                         if (len1 == 0 && len2 == 0) {
1228                                 *b = data_blob_talloc(mem_ctx, NULL, 0);
1229                         } else {
1230                                 /* make sure its in the right format - be strict */
1231                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
1232                                         return NT_STATUS_INVALID_PARAMETER;
1233                                 }
1234
1235                                 if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data)
1236                                         return NT_STATUS_INVALID_PARAMETER;     
1237                         
1238                                 *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
1239                         }
1240                         break;
1241                 case 'b':
1242                         b = (DATA_BLOB *)va_arg(ap, void *);
1243                         len1 = va_arg(ap, uint_t);
1244                         /* make sure its in the right format - be strict */
1245                         NEED_DATA(len1);
1246                         if (blob->data + head_ofs < (uint8_t *)head_ofs || blob->data + head_ofs < blob->data)
1247                                 return NT_STATUS_INVALID_PARAMETER;     
1248                         
1249                         *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
1250                         head_ofs += len1;
1251                         break;
1252                 case 'd':
1253                         v = va_arg(ap, uint32_t *);
1254                         NEED_DATA(4);
1255                         *v = IVAL(blob->data, head_ofs); head_ofs += 4;
1256                         break;
1257                 case 'C':
1258                         s = va_arg(ap, char *);
1259
1260                         if (blob->data + head_ofs < (uint8_t *)head_ofs || blob->data + head_ofs < blob->data)
1261                                 return NT_STATUS_INVALID_PARAMETER;     
1262         
1263                         head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p), 
1264                                                 blob->length - head_ofs, 
1265                                                 STR_ASCII|STR_TERMINATE);
1266                         if (strcmp(s, p) != 0) {
1267                                 return NT_STATUS_INVALID_PARAMETER;
1268                         }
1269                         break;
1270                 }
1271         }
1272         va_end(ap);
1273
1274         return NT_STATUS_OK;
1275 }