~ubuntu-branches/ubuntu/oneiric/samba/oneiric-security

« back to all changes in this revision

Viewing changes to .pc/fix-windows7-print-connection.patch/librpc/ndr/ndr.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2011-03-02 16:05:41 UTC
  • Revision ID: james.westby@ubuntu.com-20110302160541-oi1y7yhqn9qe2phs
Tags: 2:3.5.6~dfsg-5ubuntu3
* debian/patches/fix-windows7-print-connection.patch: Fix
  error "0x000003e6" when trying to connect a Windows 7 printer
  to a domain. (LP: #674216)
* debian/samba-common.dhcp: Take in account of the upstart script.
  (LP: #652065)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 3 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, see <http://www.gnu.org/licenses/>.
 
20
*/
 
21
 
 
22
/*
 
23
  this provides the core routines for NDR parsing functions
 
24
 
 
25
  see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
 
26
  of NDR encoding rules
 
27
*/
 
28
 
 
29
#include "includes.h"
 
30
#include "librpc/ndr/libndr.h"
 
31
#include "../lib/util/dlinklist.h"
 
32
#if _SAMBA_BUILD_ == 4
 
33
#include "param/param.h"
 
34
#endif
 
35
 
 
36
#define NDR_BASE_MARSHALL_SIZE 1024
 
37
 
 
38
/* this guid indicates NDR encoding in a protocol tower */
 
39
const struct ndr_syntax_id ndr_transfer_syntax = {
 
40
  { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
 
41
  2
 
42
};
 
43
 
 
44
const struct ndr_syntax_id ndr64_transfer_syntax = {
 
45
  { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
 
46
  1
 
47
};
 
48
 
 
49
/*
 
50
  work out the number of bytes needed to align on a n byte boundary
 
51
*/
 
52
_PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
 
53
{
 
54
        if ((offset & (n-1)) == 0) return 0;
 
55
        return n - (offset & (n-1));
 
56
}
 
57
 
 
58
/*
 
59
  initialise a ndr parse structure from a data blob
 
60
*/
 
61
_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
 
62
{
 
63
        struct ndr_pull *ndr;
 
64
 
 
65
        ndr = talloc_zero(mem_ctx, struct ndr_pull);
 
66
        if (!ndr) return NULL;
 
67
        ndr->current_mem_ctx = mem_ctx;
 
68
 
 
69
        ndr->data = blob->data;
 
70
        ndr->data_size = blob->length;
 
71
        ndr->iconv_convenience = talloc_reference(ndr, iconv_convenience);
 
72
 
 
73
        return ndr;
 
74
}
 
75
 
 
76
/*
 
77
  advance by 'size' bytes
 
78
*/
 
79
_PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
 
80
{
 
81
        ndr->offset += size;
 
82
        if (ndr->offset > ndr->data_size) {
 
83
                return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
 
84
                                      "ndr_pull_advance by %u failed",
 
85
                                      size);
 
86
        }
 
87
        return NDR_ERR_SUCCESS;
 
88
}
 
89
 
 
90
/*
 
91
  set the parse offset to 'ofs'
 
92
*/
 
93
static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
 
94
{
 
95
        ndr->offset = ofs;
 
96
        if (ndr->offset > ndr->data_size) {
 
97
                return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
 
98
                                      "ndr_pull_set_offset %u failed",
 
99
                                      ofs);
 
100
        }
 
101
        return NDR_ERR_SUCCESS;
 
102
}
 
103
 
 
104
/* create a ndr_push structure, ready for some marshalling */
 
105
_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
 
106
{
 
107
        struct ndr_push *ndr;
 
108
 
 
109
        ndr = talloc_zero(mem_ctx, struct ndr_push);
 
110
        if (!ndr) {
 
111
                return NULL;
 
112
        }
 
113
 
 
114
        ndr->flags = 0;
 
115
        ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
 
116
        ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
 
117
        if (!ndr->data) {
 
118
                return NULL;
 
119
        }
 
120
        ndr->iconv_convenience = talloc_reference(ndr, iconv_convenience);
 
121
 
 
122
        return ndr;
 
123
}
 
124
 
 
125
/* return a DATA_BLOB structure for the current ndr_push marshalled data */
 
126
_PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
 
127
{
 
128
        DATA_BLOB blob;
 
129
        blob = data_blob_const(ndr->data, ndr->offset);
 
130
        if (ndr->alloc_size > ndr->offset) {
 
131
                ndr->data[ndr->offset] = 0;
 
132
        }
 
133
        return blob;
 
134
}
 
135
 
 
136
 
 
137
/*
 
138
  expand the available space in the buffer to ndr->offset + extra_size
 
139
*/
 
140
_PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
 
141
{
 
142
        uint32_t size = extra_size + ndr->offset;
 
143
 
 
144
        if (size < ndr->offset) {
 
145
                /* extra_size overflowed the offset */
 
146
                return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
 
147
                                      size);
 
148
        }
 
149
 
 
150
        if (ndr->alloc_size > size) {
 
151
                return NDR_ERR_SUCCESS;
 
152
        }
 
153
 
 
154
        ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
 
155
        if (size+1 > ndr->alloc_size) {
 
156
                ndr->alloc_size = size+1;
 
157
        }
 
158
        ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
 
159
        if (!ndr->data) {
 
160
                return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
 
161
                                      ndr->alloc_size);
 
162
        }
 
163
 
 
164
        return NDR_ERR_SUCCESS;
 
165
}
 
166
 
 
167
_PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) 
 
168
{
 
169
        va_list ap;
 
170
        char *s = NULL;
 
171
        int i, ret;
 
172
 
 
173
        va_start(ap, format);
 
174
        ret = vasprintf(&s, format, ap);
 
175
        va_end(ap);
 
176
 
 
177
        if (ret == -1) {
 
178
                return;
 
179
        }
 
180
 
 
181
        for (i=0;i<ndr->depth;i++) {
 
182
                DEBUGADD(1,("    "));
 
183
        }
 
184
 
 
185
        DEBUGADD(1,("%s\n", s));
 
186
        free(s);
 
187
}
 
188
 
 
189
_PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
 
190
{
 
191
        va_list ap;
 
192
        int i;
 
193
 
 
194
        for (i=0;i<ndr->depth;i++) {
 
195
                ndr->private_data = talloc_asprintf_append_buffer(
 
196
                                        (char *)ndr->private_data, "    ");
 
197
        }
 
198
 
 
199
        va_start(ap, format);
 
200
        ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data, 
 
201
                                                    format, ap);
 
202
        va_end(ap);
 
203
        ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data, 
 
204
                                                   "\n");
 
205
}
 
206
 
 
207
/*
 
208
  a useful helper function for printing idl structures via DEBUG()
 
209
*/
 
210
_PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
 
211
{
 
212
        struct ndr_print *ndr;
 
213
 
 
214
        DEBUG(1,(" "));
 
215
 
 
216
        ndr = talloc_zero(NULL, struct ndr_print);
 
217
        if (!ndr) return;
 
218
        ndr->print = ndr_print_debug_helper;
 
219
        ndr->depth = 1;
 
220
        ndr->flags = 0;
 
221
        fn(ndr, name, ptr);
 
222
        talloc_free(ndr);
 
223
}
 
224
 
 
225
/*
 
226
  a useful helper function for printing idl unions via DEBUG()
 
227
*/
 
228
_PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
 
229
{
 
230
        struct ndr_print *ndr;
 
231
 
 
232
        DEBUG(1,(" "));
 
233
 
 
234
        ndr = talloc_zero(NULL, struct ndr_print);
 
235
        if (!ndr) return;
 
236
        ndr->print = ndr_print_debug_helper;
 
237
        ndr->depth = 1;
 
238
        ndr->flags = 0;
 
239
        ndr_print_set_switch_value(ndr, ptr, level);
 
240
        fn(ndr, name, ptr);
 
241
        talloc_free(ndr);
 
242
}
 
243
 
 
244
/*
 
245
  a useful helper function for printing idl function calls via DEBUG()
 
246
*/
 
247
_PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
 
248
{
 
249
        struct ndr_print *ndr;
 
250
 
 
251
        DEBUG(1,(" "));
 
252
 
 
253
        ndr = talloc_zero(NULL, struct ndr_print);
 
254
        if (!ndr) return;
 
255
        ndr->print = ndr_print_debug_helper;
 
256
        ndr->depth = 1;
 
257
        ndr->flags = 0;
 
258
 
 
259
        /* this is a s4 hack until we build up the courage to pass
 
260
         * this all the way down 
 
261
         */
 
262
#if _SAMBA_BUILD_ == 4
 
263
        ndr->iconv_convenience = smb_iconv_convenience_init(talloc_autofree_context(), "ASCII", "UTF-8", true);
 
264
#endif
 
265
 
 
266
        fn(ndr, name, flags, ptr);
 
267
        talloc_free(ndr);
 
268
}
 
269
 
 
270
/*
 
271
  a useful helper function for printing idl structures to a string
 
272
*/
 
273
_PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
 
274
{
 
275
        struct ndr_print *ndr;
 
276
        char *ret = NULL;
 
277
 
 
278
        ndr = talloc_zero(mem_ctx, struct ndr_print);
 
279
        if (!ndr) return NULL;
 
280
        ndr->private_data = talloc_strdup(ndr, "");
 
281
        if (!ndr->private_data) {
 
282
                goto failed;
 
283
        }
 
284
        ndr->print = ndr_print_string_helper;
 
285
        ndr->depth = 1;
 
286
        ndr->flags = 0;
 
287
 
 
288
        /* this is a s4 hack until we build up the courage to pass
 
289
         * this all the way down 
 
290
         */
 
291
#if _SAMBA_BUILD_ == 4
 
292
        ndr->iconv_convenience = smb_iconv_convenience_init(talloc_autofree_context(), "ASCII", "UTF-8", true);
 
293
#endif
 
294
 
 
295
        fn(ndr, name, ptr);
 
296
        ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
 
297
failed:
 
298
        talloc_free(ndr);
 
299
        return ret;
 
300
}
 
301
 
 
302
/*
 
303
  a useful helper function for printing idl unions to a string
 
304
*/
 
305
_PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
 
306
{
 
307
        struct ndr_print *ndr;
 
308
        char *ret = NULL;
 
309
 
 
310
        ndr = talloc_zero(mem_ctx, struct ndr_print);
 
311
        if (!ndr) return NULL;
 
312
        ndr->private_data = talloc_strdup(ndr, "");
 
313
        if (!ndr->private_data) {
 
314
                goto failed;
 
315
        }
 
316
        ndr->print = ndr_print_string_helper;
 
317
        ndr->depth = 1;
 
318
        ndr->flags = 0;
 
319
        ndr_print_set_switch_value(ndr, ptr, level);
 
320
        fn(ndr, name, ptr);
 
321
        ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
 
322
failed:
 
323
        talloc_free(ndr);
 
324
        return ret;
 
325
}
 
326
 
 
327
/*
 
328
  a useful helper function for printing idl function calls to a string
 
329
*/
 
330
_PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
 
331
                                ndr_print_function_t fn, const char *name, 
 
332
                                int flags, void *ptr)
 
333
{
 
334
        struct ndr_print *ndr;
 
335
        char *ret = NULL;
 
336
 
 
337
        ndr = talloc_zero(mem_ctx, struct ndr_print);
 
338
        if (!ndr) return NULL;
 
339
        ndr->private_data = talloc_strdup(ndr, "");
 
340
        if (!ndr->private_data) {
 
341
                goto failed;
 
342
        }
 
343
        ndr->print = ndr_print_string_helper;
 
344
        ndr->depth = 1;
 
345
        ndr->flags = 0;
 
346
        fn(ndr, name, flags, ptr);
 
347
        ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
 
348
failed:
 
349
        talloc_free(ndr);
 
350
        return ret;
 
351
}
 
352
 
 
353
_PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
 
354
{
 
355
        /* the big/little endian flags are inter-dependent */
 
356
        if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
 
357
                (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
 
358
                (*pflags) &= ~LIBNDR_FLAG_NDR64;
 
359
        }
 
360
        if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
 
361
                (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
 
362
                (*pflags) &= ~LIBNDR_FLAG_NDR64;
 
363
        }
 
364
        if (new_flags & LIBNDR_FLAG_REMAINING) {
 
365
                (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
 
366
        }
 
367
        if (new_flags & LIBNDR_ALIGN_FLAGS) {
 
368
                (*pflags) &= ~LIBNDR_FLAG_REMAINING;
 
369
        }
 
370
        if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
 
371
                (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
 
372
        }
 
373
        (*pflags) |= new_flags;
 
374
}
 
375
 
 
376
/*
 
377
  return and possibly log an NDR error
 
378
*/
 
379
_PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr,
 
380
                                 enum ndr_err_code ndr_err,
 
381
                                 const char *format, ...)
 
382
{
 
383
        char *s=NULL;
 
384
        va_list ap;
 
385
        int ret;
 
386
 
 
387
        va_start(ap, format);
 
388
        ret = vasprintf(&s, format, ap);
 
389
        va_end(ap);
 
390
 
 
391
        if (ret == -1) {
 
392
                return NDR_ERR_ALLOC;
 
393
        }
 
394
 
 
395
        DEBUG(1,("ndr_pull_error(%u): %s\n", ndr_err, s));
 
396
 
 
397
        free(s);
 
398
 
 
399
        return ndr_err;
 
400
}
 
401
 
 
402
/*
 
403
  return and possibly log an NDR error
 
404
*/
 
405
_PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr,
 
406
                                 enum ndr_err_code ndr_err,
 
407
                                 const char *format, ...) 
 
408
{
 
409
        char *s=NULL;
 
410
        va_list ap;
 
411
        int ret;
 
412
 
 
413
        va_start(ap, format);
 
414
        ret = vasprintf(&s, format, ap);
 
415
        va_end(ap);
 
416
 
 
417
        if (ret == -1) {
 
418
                return NDR_ERR_ALLOC;
 
419
        }
 
420
 
 
421
        DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err, s));
 
422
 
 
423
        free(s);
 
424
 
 
425
        return ndr_err;
 
426
}
 
427
 
 
428
/*
 
429
  handle subcontext buffers, which in midl land are user-marshalled, but
 
430
  we use magic in pidl to make them easier to cope with
 
431
*/
 
432
_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
 
433
                                   struct ndr_pull **_subndr,
 
434
                                   size_t header_size,
 
435
                                   ssize_t size_is)
 
436
{
 
437
        struct ndr_pull *subndr;
 
438
        uint32_t r_content_size;
 
439
        bool force_le = false;
 
440
        bool force_be = false;
 
441
 
 
442
        switch (header_size) {
 
443
        case 0: {
 
444
                uint32_t content_size = ndr->data_size - ndr->offset;
 
445
                if (size_is >= 0) {
 
446
                        content_size = size_is;
 
447
                }
 
448
                r_content_size = content_size;
 
449
                break;
 
450
        }
 
451
 
 
452
        case 2: {
 
453
                uint16_t content_size;
 
454
                NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
 
455
                if (size_is >= 0 && size_is != content_size) {
 
456
                        return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", 
 
457
                                                (int)size_is, (int)content_size);
 
458
                }
 
459
                r_content_size = content_size;
 
460
                break;
 
461
        }
 
462
 
 
463
        case 4: {
 
464
                uint32_t content_size;
 
465
                NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
 
466
                if (size_is >= 0 && size_is != content_size) {
 
467
                        return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", 
 
468
                                                (int)size_is, (int)content_size);
 
469
                }
 
470
                r_content_size = content_size;
 
471
                break;
 
472
        }
 
473
        case 0xFFFFFC01: {
 
474
                /*
 
475
                 * Common Type Header for the Serialization Stream
 
476
                 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
 
477
                 */
 
478
                uint8_t version;
 
479
                uint8_t drep;
 
480
                uint16_t hdrlen;
 
481
                uint32_t filler;
 
482
                uint32_t content_size;
 
483
                uint32_t reserved;
 
484
 
 
485
                /* version */
 
486
                NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
 
487
 
 
488
                if (version != 1) {
 
489
                        return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
 
490
                                              "Bad subcontext (PULL) Common Type Header version %d != 1",
 
491
                                              (int)version);
 
492
                }
 
493
 
 
494
                /*
 
495
                 * 0x10 little endian
 
496
                 * 0x00 big endian
 
497
                 */
 
498
                NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
 
499
                if (drep == 0x10) {
 
500
                        force_le = true;
 
501
                } else if (drep == 0x00) {
 
502
                        force_be = true;
 
503
                } else {
 
504
                        return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
 
505
                                              "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
 
506
                                              (unsigned int)drep);
 
507
                }
 
508
 
 
509
                /* length of the "Private Header for Constructed Type" */
 
510
                NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
 
511
                if (hdrlen != 8) {
 
512
                        return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
 
513
                                              "Bad subcontext (PULL) Common Type Header length %d != 8",
 
514
                                              (int)hdrlen);
 
515
                }
 
516
 
 
517
                /* filler should be ignored */
 
518
                NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
 
519
 
 
520
                /*
 
521
                 * Private Header for Constructed Type
 
522
                 */
 
523
                /* length - will be updated latter */
 
524
                NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
 
525
                if (size_is >= 0 && size_is != content_size) {
 
526
                        return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
 
527
                                              (int)size_is, (int)content_size);
 
528
                }
 
529
                /* the content size must be a multiple of 8 */
 
530
                if ((content_size % 8) != 0) {
 
531
                        return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
 
532
                                              "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
 
533
                                              (int)size_is, (int)content_size);
 
534
                }
 
535
                r_content_size = content_size;
 
536
 
 
537
                /* reserved */
 
538
                NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
 
539
                break;
 
540
        }
 
541
        default:
 
542
                return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d", 
 
543
                                      (int)header_size);
 
544
        }
 
545
 
 
546
        NDR_PULL_NEED_BYTES(ndr, r_content_size);
 
547
 
 
548
        subndr = talloc_zero(ndr, struct ndr_pull);
 
549
        NDR_ERR_HAVE_NO_MEMORY(subndr);
 
550
        subndr->flags           = ndr->flags & ~LIBNDR_FLAG_NDR64;
 
551
        subndr->current_mem_ctx = ndr->current_mem_ctx;
 
552
 
 
553
        subndr->data = ndr->data + ndr->offset;
 
554
        subndr->offset = 0;
 
555
        subndr->data_size = r_content_size;
 
556
        subndr->iconv_convenience = talloc_reference(subndr, ndr->iconv_convenience);
 
557
 
 
558
        if (force_le) {
 
559
                ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
 
560
        } else if (force_be) {
 
561
                ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
 
562
        }
 
563
 
 
564
        *_subndr = subndr;
 
565
        return NDR_ERR_SUCCESS;
 
566
}
 
567
 
 
568
_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
 
569
                                 struct ndr_pull *subndr,
 
570
                                 size_t header_size,
 
571
                                 ssize_t size_is)
 
572
{
 
573
        uint32_t advance;
 
574
        if (size_is >= 0) {
 
575
                advance = size_is;
 
576
        } else if (header_size > 0) {
 
577
                advance = subndr->data_size;
 
578
        } else {
 
579
                advance = subndr->offset;
 
580
        }
 
581
        NDR_CHECK(ndr_pull_advance(ndr, advance));
 
582
        return NDR_ERR_SUCCESS;
 
583
}
 
584
 
 
585
_PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
 
586
                                   struct ndr_push **_subndr,
 
587
                                   size_t header_size,
 
588
                                   ssize_t size_is)
 
589
{
 
590
        struct ndr_push *subndr;
 
591
 
 
592
        subndr = ndr_push_init_ctx(ndr, ndr->iconv_convenience);
 
593
        NDR_ERR_HAVE_NO_MEMORY(subndr);
 
594
        subndr->flags   = ndr->flags & ~LIBNDR_FLAG_NDR64;
 
595
 
 
596
        if (size_is > 0) {
 
597
                NDR_CHECK(ndr_push_zero(subndr, size_is));
 
598
                subndr->offset = 0;
 
599
                subndr->relative_end_offset = size_is;
 
600
        }
 
601
 
 
602
        *_subndr = subndr;
 
603
        return NDR_ERR_SUCCESS;
 
604
}
 
605
 
 
606
/*
 
607
  push a subcontext header 
 
608
*/
 
609
_PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
 
610
                                 struct ndr_push *subndr,
 
611
                                 size_t header_size,
 
612
                                 ssize_t size_is)
 
613
{
 
614
        ssize_t padding_len;
 
615
 
 
616
        if (size_is >= 0) {
 
617
                padding_len = size_is - subndr->offset;
 
618
                if (padding_len < 0) {
 
619
                        return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
 
620
                                              (int)subndr->offset, (int)size_is);
 
621
                }
 
622
                subndr->offset = size_is;
 
623
        }
 
624
 
 
625
        switch (header_size) {
 
626
        case 0: 
 
627
                break;
 
628
 
 
629
        case 2: 
 
630
                NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
 
631
                break;
 
632
 
 
633
        case 4: 
 
634
                NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
 
635
                break;
 
636
 
 
637
        case 0xFFFFFC01:
 
638
                /*
 
639
                 * Common Type Header for the Serialization Stream
 
640
                 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
 
641
                 */
 
642
                padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
 
643
                if (padding_len > 0) {
 
644
                        NDR_CHECK(ndr_push_zero(subndr, padding_len));
 
645
                }
 
646
 
 
647
                /* version */
 
648
                NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
 
649
 
 
650
                /*
 
651
                 * 0x10 little endian
 
652
                 * 0x00 big endian
 
653
                 */
 
654
                NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
 
655
 
 
656
                /* length of the "Private Header for Constructed Type" */
 
657
                NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
 
658
 
 
659
                /* filler */
 
660
                NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
 
661
 
 
662
                /*
 
663
                 * Private Header for Constructed Type
 
664
                 */
 
665
                /* length - will be updated latter */
 
666
                NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
 
667
 
 
668
                /* reserved */
 
669
                NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
 
670
                break;
 
671
 
 
672
        default:
 
673
                return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d", 
 
674
                                      (int)header_size);
 
675
        }
 
676
 
 
677
        NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
 
678
        return NDR_ERR_SUCCESS;
 
679
}
 
680
 
 
681
/*
 
682
  store a token in the ndr context, for later retrieval
 
683
*/
 
684
_PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
 
685
                         struct ndr_token_list **list, 
 
686
                         const void *key, 
 
687
                         uint32_t value)
 
688
{
 
689
        struct ndr_token_list *tok;
 
690
        tok = talloc(mem_ctx, struct ndr_token_list);
 
691
        NDR_ERR_HAVE_NO_MEMORY(tok);
 
692
        tok->key = key;
 
693
        tok->value = value;
 
694
        DLIST_ADD((*list), tok);
 
695
        return NDR_ERR_SUCCESS;
 
696
}
 
697
 
 
698
/*
 
699
  retrieve a token from a ndr context, using cmp_fn to match the tokens
 
700
*/
 
701
_PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v,
 
702
                                   comparison_fn_t _cmp_fn, bool _remove_tok)
 
703
{
 
704
        struct ndr_token_list *tok;
 
705
        for (tok=*list;tok;tok=tok->next) {
 
706
                if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found;
 
707
                else if (!_cmp_fn && tok->key == key) goto found;
 
708
        }
 
709
        return NDR_ERR_TOKEN;
 
710
found:
 
711
        *v = tok->value;
 
712
        if (_remove_tok) {
 
713
                DLIST_REMOVE((*list), tok);
 
714
                talloc_free(tok);
 
715
        }
 
716
        return NDR_ERR_SUCCESS;
 
717
}
 
718
 
 
719
/*
 
720
  retrieve a token from a ndr context
 
721
*/
 
722
_PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
 
723
{
 
724
        return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
 
725
}
 
726
 
 
727
/*
 
728
  peek at but don't removed a token from a ndr context
 
729
*/
 
730
_PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
 
731
{
 
732
        enum ndr_err_code status;
 
733
        uint32_t v;
 
734
 
 
735
        status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, false);
 
736
        if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
 
737
                return 0;
 
738
        }
 
739
 
 
740
        return v;
 
741
}
 
742
 
 
743
/*
 
744
  pull an array size field and add it to the array_size_list token list
 
745
*/
 
746
_PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
 
747
{
 
748
        uint32_t size;
 
749
        NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
 
750
        return ndr_token_store(ndr, &ndr->array_size_list, p, size);
 
751
}
 
752
 
 
753
/*
 
754
  get the stored array size field
 
755
*/
 
756
_PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
 
757
{
 
758
        return ndr_token_peek(&ndr->array_size_list, p);
 
759
}
 
760
 
 
761
/*
 
762
  check the stored array size field
 
763
*/
 
764
_PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
 
765
{
 
766
        uint32_t stored;
 
767
        stored = ndr_token_peek(&ndr->array_size_list, p);
 
768
        if (stored != size) {
 
769
                return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
 
770
                                      "Bad array size - got %u expected %u\n",
 
771
                                      stored, size);
 
772
        }
 
773
        return NDR_ERR_SUCCESS;
 
774
}
 
775
 
 
776
/*
 
777
  pull an array length field and add it to the array_length_list token list
 
778
*/
 
779
_PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
 
780
{
 
781
        uint32_t length, offset;
 
782
        NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
 
783
        if (offset != 0) {
 
784
                return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
 
785
                                      "non-zero array offset %u\n", offset);
 
786
        }
 
787
        NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
 
788
        return ndr_token_store(ndr, &ndr->array_length_list, p, length);
 
789
}
 
790
 
 
791
/*
 
792
  get the stored array length field
 
793
*/
 
794
_PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
 
795
{
 
796
        return ndr_token_peek(&ndr->array_length_list, p);
 
797
}
 
798
 
 
799
/*
 
800
  check the stored array length field
 
801
*/
 
802
_PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
 
803
{
 
804
        uint32_t stored;
 
805
        stored = ndr_token_peek(&ndr->array_length_list, p);
 
806
        if (stored != length) {
 
807
                return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
 
808
                                      "Bad array length - got %u expected %u\n",
 
809
                                      stored, length);
 
810
        }
 
811
        return NDR_ERR_SUCCESS;
 
812
}
 
813
 
 
814
/*
 
815
  store a switch value
 
816
 */
 
817
_PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
 
818
{
 
819
        return ndr_token_store(ndr, &ndr->switch_list, p, val);
 
820
}
 
821
 
 
822
_PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
 
823
{
 
824
        return ndr_token_store(ndr, &ndr->switch_list, p, val);
 
825
}
 
826
 
 
827
_PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
 
828
{
 
829
        return ndr_token_store(ndr, &ndr->switch_list, p, val);
 
830
}
 
831
 
 
832
/*
 
833
  retrieve a switch value
 
834
 */
 
835
_PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
 
836
{
 
837
        return ndr_token_peek(&ndr->switch_list, p);
 
838
}
 
839
 
 
840
_PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
 
841
{
 
842
        return ndr_token_peek(&ndr->switch_list, p);
 
843
}
 
844
 
 
845
_PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
 
846
{
 
847
        return ndr_token_peek(&ndr->switch_list, p);
 
848
}
 
849
 
 
850
/*
 
851
  pull a struct from a blob using NDR
 
852
*/
 
853
_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, void *p,
 
854
                              ndr_pull_flags_fn_t fn)
 
855
{
 
856
        struct ndr_pull *ndr;
 
857
        ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
 
858
        NDR_ERR_HAVE_NO_MEMORY(ndr);
 
859
        NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
 
860
        talloc_free(ndr);
 
861
        return NDR_ERR_SUCCESS;
 
862
}
 
863
 
 
864
/*
 
865
  pull a struct from a blob using NDR - failing if all bytes are not consumed
 
866
*/
 
867
_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
 
868
                                                    struct smb_iconv_convenience *iconv_convenience,
 
869
                                                    void *p, ndr_pull_flags_fn_t fn)
 
870
{
 
871
        struct ndr_pull *ndr;
 
872
        ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
 
873
        NDR_ERR_HAVE_NO_MEMORY(ndr);
 
874
        NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
 
875
        if (ndr->offset < ndr->data_size) {
 
876
                return ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
 
877
                                      "not all bytes consumed ofs[%u] size[%u]",
 
878
                                      ndr->offset, ndr->data_size);
 
879
        }
 
880
        talloc_free(ndr);
 
881
        return NDR_ERR_SUCCESS;
 
882
}
 
883
 
 
884
/*
 
885
  pull a union from a blob using NDR, given the union discriminator
 
886
*/
 
887
_PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
 
888
                                               struct smb_iconv_convenience *iconv_convenience, void *p,
 
889
                             uint32_t level, ndr_pull_flags_fn_t fn)
 
890
{
 
891
        struct ndr_pull *ndr;
 
892
        ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
 
893
        NDR_ERR_HAVE_NO_MEMORY(ndr);
 
894
        NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
 
895
        NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
 
896
        talloc_free(ndr);
 
897
        return NDR_ERR_SUCCESS;
 
898
}
 
899
 
 
900
/*
 
901
  pull a union from a blob using NDR, given the union discriminator,
 
902
  failing if all bytes are not consumed
 
903
*/
 
904
_PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
 
905
                                                   struct smb_iconv_convenience *iconv_convenience, void *p,
 
906
                             uint32_t level, ndr_pull_flags_fn_t fn)
 
907
{
 
908
        struct ndr_pull *ndr;
 
909
        ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
 
910
        NDR_ERR_HAVE_NO_MEMORY(ndr);
 
911
        NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
 
912
        NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
 
913
        if (ndr->offset < ndr->data_size) {
 
914
                enum ndr_err_code ret;
 
915
                ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
 
916
                                     "not all bytes consumed ofs[%u] size[%u]",
 
917
                                     ndr->offset, ndr->data_size);
 
918
                talloc_free(ndr);
 
919
                return ret;
 
920
        }
 
921
        talloc_free(ndr);
 
922
        return NDR_ERR_SUCCESS;
 
923
}
 
924
 
 
925
/*
 
926
  push a struct to a blob using NDR
 
927
*/
 
928
_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, const void *p, ndr_push_flags_fn_t fn)
 
929
{
 
930
        struct ndr_push *ndr;
 
931
        ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
 
932
        NDR_ERR_HAVE_NO_MEMORY(ndr);
 
933
 
 
934
        NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
 
935
 
 
936
        *blob = ndr_push_blob(ndr);
 
937
        talloc_steal(mem_ctx, blob->data);
 
938
        talloc_free(ndr);
 
939
 
 
940
        return NDR_ERR_SUCCESS;
 
941
}
 
942
 
 
943
/*
 
944
  push a union to a blob using NDR
 
945
*/
 
946
_PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, void *p,
 
947
                             uint32_t level, ndr_push_flags_fn_t fn)
 
948
{
 
949
        struct ndr_push *ndr;
 
950
        ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
 
951
        NDR_ERR_HAVE_NO_MEMORY(ndr);
 
952
 
 
953
        NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
 
954
        NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
 
955
 
 
956
        *blob = ndr_push_blob(ndr);
 
957
        talloc_steal(mem_ctx, blob->data);
 
958
        talloc_free(ndr);
 
959
 
 
960
        return NDR_ERR_SUCCESS;
 
961
}
 
962
 
 
963
/*
 
964
  generic ndr_size_*() handler for structures
 
965
*/
 
966
_PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push, struct smb_iconv_convenience *iconv_convenience)
 
967
{
 
968
        struct ndr_push *ndr;
 
969
        enum ndr_err_code status;
 
970
        size_t ret;
 
971
 
 
972
        /* avoid recursion */
 
973
        if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
 
974
 
 
975
        ndr = ndr_push_init_ctx(NULL, iconv_convenience);
 
976
        if (!ndr) return 0;
 
977
        ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
 
978
        status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
 
979
        if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
 
980
                talloc_free(ndr);
 
981
                return 0;
 
982
        }
 
983
        ret = ndr->offset;
 
984
        talloc_free(ndr);
 
985
        return ret;
 
986
}
 
987
 
 
988
/*
 
989
  generic ndr_size_*() handler for unions
 
990
*/
 
991
_PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push, struct smb_iconv_convenience *iconv_convenience)
 
992
{
 
993
        struct ndr_push *ndr;
 
994
        enum ndr_err_code status;
 
995
        size_t ret;
 
996
 
 
997
        /* avoid recursion */
 
998
        if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
 
999
 
 
1000
        ndr = ndr_push_init_ctx(NULL, iconv_convenience);
 
1001
        if (!ndr) return 0;
 
1002
        ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
 
1003
 
 
1004
        status = ndr_push_set_switch_value(ndr, p, level);
 
1005
        if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
 
1006
                talloc_free(ndr);
 
1007
                return 0;
 
1008
        }
 
1009
        status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
 
1010
        if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
 
1011
                talloc_free(ndr);
 
1012
                return 0;
 
1013
        }
 
1014
        ret = ndr->offset;
 
1015
        talloc_free(ndr);
 
1016
        return ret;
 
1017
}
 
1018
 
 
1019
/*
 
1020
  get the current base for relative pointers for the push
 
1021
*/
 
1022
_PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
 
1023
{
 
1024
        return ndr->relative_base_offset;
 
1025
}
 
1026
 
 
1027
/*
 
1028
  restore the old base for relative pointers for the push
 
1029
*/
 
1030
_PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
 
1031
{
 
1032
        ndr->relative_base_offset = offset;
 
1033
}
 
1034
 
 
1035
/*
 
1036
  setup the current base for relative pointers for the push
 
1037
  called in the NDR_SCALAR stage
 
1038
*/
 
1039
_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
 
1040
{
 
1041
        ndr->relative_base_offset = offset;
 
1042
        return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
 
1043
}
 
1044
 
 
1045
/*
 
1046
  setup the current base for relative pointers for the push
 
1047
  called in the NDR_BUFFERS stage
 
1048
*/
 
1049
_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
 
1050
{
 
1051
        return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
 
1052
}
 
1053
 
 
1054
/*
 
1055
  push a relative object - stage1
 
1056
  this is called during SCALARS processing
 
1057
*/
 
1058
_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
 
1059
{
 
1060
        if (p == NULL) {
 
1061
                NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
 
1062
                return NDR_ERR_SUCCESS;
 
1063
        }
 
1064
        NDR_CHECK(ndr_push_align(ndr, 4));
 
1065
        NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
 
1066
        return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
 
1067
}
 
1068
 
 
1069
/*
 
1070
  push a relative object - stage2
 
1071
  this is called during buffers processing
 
1072
*/
 
1073
static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
 
1074
{
 
1075
        uint32_t save_offset;
 
1076
        uint32_t ptr_offset = 0xFFFFFFFF;
 
1077
        if (p == NULL) {
 
1078
                return NDR_ERR_SUCCESS;
 
1079
        }
 
1080
        save_offset = ndr->offset;
 
1081
        NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
 
1082
        if (ptr_offset > ndr->offset) {
 
1083
                return ndr_push_error(ndr, NDR_ERR_BUFSIZE, 
 
1084
                                      "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
 
1085
                                      ptr_offset, ndr->offset);
 
1086
        }
 
1087
        ndr->offset = ptr_offset;
 
1088
        if (save_offset < ndr->relative_base_offset) {
 
1089
                return ndr_push_error(ndr, NDR_ERR_BUFSIZE, 
 
1090
                                      "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
 
1091
                                      save_offset, ndr->relative_base_offset);
 
1092
        }       
 
1093
        NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
 
1094
        ndr->offset = save_offset;
 
1095
        return NDR_ERR_SUCCESS;
 
1096
}
 
1097
 
 
1098
/*
 
1099
  push a relative object - stage2 start
 
1100
  this is called during buffers processing
 
1101
*/
 
1102
_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
 
1103
{
 
1104
        if (p == NULL) {
 
1105
                return NDR_ERR_SUCCESS;
 
1106
        }
 
1107
        if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
 
1108
                return ndr_push_relative_ptr2(ndr, p);
 
1109
        }
 
1110
        if (ndr->relative_end_offset == -1) {
 
1111
                return ndr_push_error(ndr, NDR_ERR_RELATIVE,
 
1112
                              "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
 
1113
                              ndr->relative_end_offset);
 
1114
        }
 
1115
        NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset));
 
1116
        return NDR_ERR_SUCCESS;
 
1117
}
 
1118
 
 
1119
/*
 
1120
  push a relative object - stage2 end
 
1121
  this is called during buffers processing
 
1122
*/
 
1123
_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
 
1124
{
 
1125
        uint32_t begin_offset = 0xFFFFFFFF;
 
1126
        ssize_t len;
 
1127
        uint32_t correct_offset = 0;
 
1128
        uint32_t align = 1;
 
1129
        uint32_t pad = 0;
 
1130
 
 
1131
        if (p == NULL) {
 
1132
                return NDR_ERR_SUCCESS;
 
1133
        }
 
1134
 
 
1135
        if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
 
1136
                return NDR_ERR_SUCCESS;
 
1137
        }
 
1138
 
 
1139
        if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
 
1140
                /* better say more than calculation a too small buffer */
 
1141
                NDR_PUSH_ALIGN(ndr, 8);
 
1142
                return NDR_ERR_SUCCESS;
 
1143
        }
 
1144
 
 
1145
        if (ndr->relative_end_offset < ndr->offset) {
 
1146
                return ndr_push_error(ndr, NDR_ERR_RELATIVE,
 
1147
                                      "ndr_push_relative_ptr2_end:"
 
1148
                                      "relative_end_offset %u < offset %u",
 
1149
                                      ndr->relative_end_offset, ndr->offset);
 
1150
        }
 
1151
 
 
1152
        NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
 
1153
 
 
1154
        /* we have marshalled a buffer, see how long it was */
 
1155
        len = ndr->offset - begin_offset;
 
1156
 
 
1157
        if (len < 0) {
 
1158
                return ndr_push_error(ndr, NDR_ERR_RELATIVE,
 
1159
                                      "ndr_push_relative_ptr2_end:"
 
1160
                                      "offset %u - begin_offset %u < 0",
 
1161
                                      ndr->offset, begin_offset);
 
1162
        }
 
1163
 
 
1164
        if (ndr->relative_end_offset < len) {
 
1165
                return ndr_push_error(ndr, NDR_ERR_RELATIVE,
 
1166
                                      "ndr_push_relative_ptr2_end:"
 
1167
                                      "relative_end_offset %u < len %lld",
 
1168
                                      ndr->offset, (long long)len);
 
1169
        }
 
1170
 
 
1171
        /* the reversed offset is at the end of the main buffer */
 
1172
        correct_offset = ndr->relative_end_offset - len;
 
1173
 
 
1174
        /* TODO: remove this hack and let the idl use FLAG_ALIGN2 explicit */
 
1175
        align = 2;
 
1176
 
 
1177
        if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
 
1178
                align = 2;
 
1179
        } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
 
1180
                align = 4;
 
1181
        } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
 
1182
                align = 8;
 
1183
        }
 
1184
 
 
1185
        pad = ndr_align_size(correct_offset, align);
 
1186
        if (pad) {
 
1187
                correct_offset += pad;
 
1188
                correct_offset -= align;
 
1189
        }
 
1190
 
 
1191
        if (correct_offset < begin_offset) {
 
1192
                return ndr_push_error(ndr, NDR_ERR_RELATIVE,
 
1193
                                      "ndr_push_relative_ptr2_end: "
 
1194
                                      "correct_offset %u < begin_offset %u",
 
1195
                                      correct_offset, begin_offset);
 
1196
        }
 
1197
 
 
1198
        if (len > 0) {
 
1199
                uint32_t clear_size = correct_offset - begin_offset;
 
1200
 
 
1201
                clear_size = MIN(clear_size, len);
 
1202
 
 
1203
                /* now move the marshalled buffer to the end of the main buffer */
 
1204
                memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
 
1205
 
 
1206
                if (clear_size) {
 
1207
                        /* and wipe out old buffer within the main buffer */
 
1208
                        memset(ndr->data + begin_offset, '\0', clear_size);
 
1209
                }
 
1210
        }
 
1211
 
 
1212
        /* and set the end offset for the next buffer */
 
1213
        ndr->relative_end_offset = correct_offset;
 
1214
 
 
1215
        /* finally write the offset to the main buffer */
 
1216
        ndr->offset = correct_offset;
 
1217
        NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
 
1218
 
 
1219
        /* restore to where we were in the main buffer */
 
1220
        ndr->offset = begin_offset;
 
1221
 
 
1222
        return NDR_ERR_SUCCESS;
 
1223
}
 
1224
 
 
1225
/*
 
1226
  get the current base for relative pointers for the pull
 
1227
*/
 
1228
_PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
 
1229
{
 
1230
        return ndr->relative_base_offset;
 
1231
}
 
1232
 
 
1233
/*
 
1234
  restore the old base for relative pointers for the pull
 
1235
*/
 
1236
_PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
 
1237
{
 
1238
        ndr->relative_base_offset = offset;
 
1239
}
 
1240
 
 
1241
/*
 
1242
  setup the current base for relative pointers for the pull
 
1243
  called in the NDR_SCALAR stage
 
1244
*/
 
1245
_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
 
1246
{
 
1247
        ndr->relative_base_offset = offset;
 
1248
        return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
 
1249
}
 
1250
 
 
1251
/*
 
1252
  setup the current base for relative pointers for the pull
 
1253
  called in the NDR_BUFFERS stage
 
1254
*/
 
1255
_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
 
1256
{
 
1257
        return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
 
1258
}
 
1259
 
 
1260
/*
 
1261
  pull a relative object - stage1
 
1262
  called during SCALARS processing
 
1263
*/
 
1264
_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
 
1265
{
 
1266
        rel_offset += ndr->relative_base_offset;
 
1267
        if (rel_offset > ndr->data_size) {
 
1268
                return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
 
1269
                                      "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
 
1270
                                      rel_offset, ndr->data_size);
 
1271
        }
 
1272
        return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
 
1273
}
 
1274
 
 
1275
/*
 
1276
  pull a relative object - stage2
 
1277
  called during BUFFERS processing
 
1278
*/
 
1279
_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
 
1280
{
 
1281
        uint32_t rel_offset;
 
1282
        NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
 
1283
        return ndr_pull_set_offset(ndr, rel_offset);
 
1284
}
 
1285
 
 
1286
const static struct {
 
1287
        enum ndr_err_code err;
 
1288
        const char *string;
 
1289
} ndr_err_code_strings[] = {
 
1290
        { NDR_ERR_SUCCESS, "Success" },
 
1291
        { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
 
1292
        { NDR_ERR_BAD_SWITCH, "Bad Switch" },
 
1293
        { NDR_ERR_OFFSET, "Offset Error" },
 
1294
        { NDR_ERR_RELATIVE, "Relative Pointer Error" },
 
1295
        { NDR_ERR_CHARCNV, "Character Conversion Error" },
 
1296
        { NDR_ERR_LENGTH, "Length Error" },
 
1297
        { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
 
1298
        { NDR_ERR_COMPRESSION, "Compression Error" },
 
1299
        { NDR_ERR_STRING, "String Error" },
 
1300
        { NDR_ERR_VALIDATE, "Validate Error" },
 
1301
        { NDR_ERR_BUFSIZE, "Buffer Size Error" },
 
1302
        { NDR_ERR_ALLOC, "Allocation Error" },
 
1303
        { NDR_ERR_RANGE, "Range Error" },
 
1304
        { NDR_ERR_TOKEN, "Token Error" },
 
1305
        { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
 
1306
        { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
 
1307
        { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
 
1308
        { NDR_ERR_NDR64, "NDR64 assertion error" },
 
1309
        { 0, NULL }
 
1310
};
 
1311
 
 
1312
_PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
 
1313
{
 
1314
        int i;
 
1315
        for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
 
1316
                if (ndr_err_code_strings[i].err == ndr_err)
 
1317
                        return ndr_err_code_strings[i].string;
 
1318
        }
 
1319
        return "Unknown error";
 
1320
}