~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/rpc_parse/parse_prs.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   Samba memory buffer functions
 
4
   Copyright (C) Andrew Tridgell              1992-1997
 
5
   Copyright (C) Luke Kenneth Casson Leighton 1996-1997
 
6
   Copyright (C) Jeremy Allison               1999
 
7
   Copyright (C) Andrew Bartlett              2003.
 
8
   
 
9
   This program is free software; you can redistribute it and/or modify
 
10
   it under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation; either version 3 of the License, or
 
12
   (at your option) any later version.
 
13
   
 
14
   This program is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
   
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
*/
 
22
 
 
23
#include "includes.h"
 
24
 
 
25
#undef DBGC_CLASS
 
26
#define DBGC_CLASS DBGC_RPC_PARSE
 
27
 
 
28
/**
 
29
 * Dump a prs to a file: from the current location through to the end.
 
30
 **/
 
31
void prs_dump(const char *name, int v, prs_struct *ps)
 
32
{
 
33
        prs_dump_region(name, v, ps, ps->data_offset, ps->buffer_size);
 
34
}
 
35
 
 
36
/**
 
37
 * Dump from the start of the prs to the current location.
 
38
 **/
 
39
void prs_dump_before(const char *name, int v, prs_struct *ps)
 
40
{
 
41
        prs_dump_region(name, v, ps, 0, ps->data_offset);
 
42
}
 
43
 
 
44
/**
 
45
 * Dump everything from the start of the prs up to the current location.
 
46
 **/
 
47
void prs_dump_region(const char *name, int v, prs_struct *ps,
 
48
                     int from_off, int to_off)
 
49
{
 
50
        int fd, i;
 
51
        char *fname = NULL;
 
52
        ssize_t sz;
 
53
        if (DEBUGLEVEL < 50) return;
 
54
        for (i=1;i<100;i++) {
 
55
                if (v != -1) {
 
56
                        if (asprintf(&fname,"/tmp/%s_%d.%d.prs", name, v, i) < 0) {
 
57
                                return;
 
58
                        }
 
59
                } else {
 
60
                        if (asprintf(&fname,"/tmp/%s.%d.prs", name, i) < 0) {
 
61
                                return;
 
62
                        }
 
63
                }
 
64
                fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
 
65
                if (fd != -1 || errno != EEXIST) break;
 
66
        }
 
67
        if (fd != -1) {
 
68
                sz = write(fd, ps->data_p + from_off, to_off - from_off);
 
69
                i = close(fd);
 
70
                if ( (sz != to_off-from_off) || (i != 0) ) {
 
71
                        DEBUG(0,("Error writing/closing %s: %ld!=%ld %d\n", fname, (unsigned long)sz, (unsigned long)to_off-from_off, i ));
 
72
                } else {
 
73
                        DEBUG(0,("created %s\n", fname));
 
74
                }
 
75
        }
 
76
        SAFE_FREE(fname);
 
77
}
 
78
 
 
79
/*******************************************************************
 
80
 Debug output for parsing info
 
81
 
 
82
 XXXX side-effect of this function is to increase the debug depth XXXX.
 
83
 
 
84
********************************************************************/
 
85
 
 
86
void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name)
 
87
{
 
88
        DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(5+depth,depth), ps->data_offset, fn_name, desc));
 
89
}
 
90
 
 
91
/**
 
92
 * Initialise an expandable parse structure.
 
93
 *
 
94
 * @param size Initial buffer size.  If >0, a new buffer will be
 
95
 * created with malloc().
 
96
 *
 
97
 * @return False if allocation fails, otherwise True.
 
98
 **/
 
99
 
 
100
bool prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, bool io)
 
101
{
 
102
        ZERO_STRUCTP(ps);
 
103
        ps->io = io;
 
104
        ps->bigendian_data = RPC_LITTLE_ENDIAN;
 
105
        ps->align = RPC_PARSE_ALIGN;
 
106
        ps->is_dynamic = False;
 
107
        ps->data_offset = 0;
 
108
        ps->buffer_size = 0;
 
109
        ps->data_p = NULL;
 
110
        ps->mem_ctx = ctx;
 
111
 
 
112
        if (size != 0) {
 
113
                ps->buffer_size = size;
 
114
                if((ps->data_p = (char *)SMB_MALLOC((size_t)size)) == NULL) {
 
115
                        DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
 
116
                        return False;
 
117
                }
 
118
                memset(ps->data_p, '\0', (size_t)size);
 
119
                ps->is_dynamic = True; /* We own this memory. */
 
120
        } else if (MARSHALLING(ps)) {
 
121
                /* If size is zero and we're marshalling we should allocate memory on demand. */
 
122
                ps->is_dynamic = True;
 
123
        }
 
124
 
 
125
        return True;
 
126
}
 
127
 
 
128
/*******************************************************************
 
129
 Delete the memory in a parse structure - if we own it.
 
130
 
 
131
 NOTE: Contrary to the somewhat confusing naming, this function is not
 
132
       intended for freeing memory allocated by prs_alloc_mem().  That memory
 
133
       is attached to the talloc context given by ps->mem_ctx.
 
134
 ********************************************************************/
 
135
 
 
136
void prs_mem_free(prs_struct *ps)
 
137
{
 
138
        if(ps->is_dynamic)
 
139
                SAFE_FREE(ps->data_p);
 
140
        ps->is_dynamic = False;
 
141
        ps->buffer_size = 0;
 
142
        ps->data_offset = 0;
 
143
}
 
144
 
 
145
/*******************************************************************
 
146
 Clear the memory in a parse structure.
 
147
 ********************************************************************/
 
148
 
 
149
void prs_mem_clear(prs_struct *ps)
 
150
{
 
151
        if (ps->buffer_size)
 
152
                memset(ps->data_p, '\0', (size_t)ps->buffer_size);
 
153
}
 
154
 
 
155
/*******************************************************************
 
156
 Allocate memory when unmarshalling... Always zero clears.
 
157
 ********************************************************************/
 
158
 
 
159
#if defined(PARANOID_MALLOC_CHECKER)
 
160
char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count)
 
161
#else
 
162
char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count)
 
163
#endif
 
164
{
 
165
        char *ret = NULL;
 
166
 
 
167
        if (size && count) {
 
168
                /* We can't call the type-safe version here. */
 
169
                ret = (char *)_talloc_zero_array(ps->mem_ctx, size, count,
 
170
                                                 "parse_prs");
 
171
        }
 
172
        return ret;
 
173
}
 
174
 
 
175
/*******************************************************************
 
176
 Return the current talloc context we're using.
 
177
 ********************************************************************/
 
178
 
 
179
TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
 
180
{
 
181
        return ps->mem_ctx;
 
182
}
 
183
 
 
184
/*******************************************************************
 
185
 Hand some already allocated memory to a prs_struct.
 
186
 ********************************************************************/
 
187
 
 
188
void prs_give_memory(prs_struct *ps, char *buf, uint32 size, bool is_dynamic)
 
189
{
 
190
        ps->is_dynamic = is_dynamic;
 
191
        ps->data_p = buf;
 
192
        ps->buffer_size = size;
 
193
}
 
194
 
 
195
/*******************************************************************
 
196
 Take some memory back from a prs_struct.
 
197
 ********************************************************************/
 
198
 
 
199
char *prs_take_memory(prs_struct *ps, uint32 *psize)
 
200
{
 
201
        char *ret = ps->data_p;
 
202
        if(psize)
 
203
                *psize = ps->buffer_size;
 
204
        ps->is_dynamic = False;
 
205
        prs_mem_free(ps);
 
206
        return ret;
 
207
}
 
208
 
 
209
/*******************************************************************
 
210
 Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
 
211
 ********************************************************************/
 
212
 
 
213
bool prs_set_buffer_size(prs_struct *ps, uint32 newsize)
 
214
{
 
215
        if (newsize > ps->buffer_size)
 
216
                return prs_force_grow(ps, newsize - ps->buffer_size);
 
217
 
 
218
        if (newsize < ps->buffer_size) {
 
219
                ps->buffer_size = newsize;
 
220
 
 
221
                /* newsize == 0 acts as a free and set pointer to NULL */
 
222
                if (newsize == 0) {
 
223
                        SAFE_FREE(ps->data_p);
 
224
                } else {
 
225
                        ps->data_p = (char *)SMB_REALLOC(ps->data_p, newsize);
 
226
 
 
227
                        if (ps->data_p == NULL) {
 
228
                                DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
 
229
                                        (unsigned int)newsize));
 
230
                                DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
 
231
                                return False;
 
232
                        }
 
233
                }
 
234
        }
 
235
 
 
236
        return True;
 
237
}
 
238
 
 
239
/*******************************************************************
 
240
 Attempt, if needed, to grow a data buffer.
 
241
 Also depends on the data stream mode (io).
 
242
 ********************************************************************/
 
243
 
 
244
bool prs_grow(prs_struct *ps, uint32 extra_space)
 
245
{
 
246
        uint32 new_size;
 
247
 
 
248
        ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
 
249
 
 
250
        if(ps->data_offset + extra_space <= ps->buffer_size)
 
251
                return True;
 
252
 
 
253
        /*
 
254
         * We cannot grow the buffer if we're not reading
 
255
         * into the prs_struct, or if we don't own the memory.
 
256
         */
 
257
 
 
258
        if(UNMARSHALLING(ps) || !ps->is_dynamic) {
 
259
                DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
 
260
                                (unsigned int)extra_space));
 
261
                return False;
 
262
        }
 
263
        
 
264
        /*
 
265
         * Decide how much extra space we really need.
 
266
         */
 
267
 
 
268
        extra_space -= (ps->buffer_size - ps->data_offset);
 
269
        if(ps->buffer_size == 0) {
 
270
 
 
271
                /*
 
272
                 * Start with 128 bytes (arbitrary value), enough for small rpc
 
273
                 * requests
 
274
                 */
 
275
                new_size = MAX(128, extra_space);
 
276
 
 
277
                if((ps->data_p = (char *)SMB_MALLOC(new_size)) == NULL) {
 
278
                        DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
 
279
                        return False;
 
280
                }
 
281
                memset(ps->data_p, '\0', (size_t)new_size );
 
282
        } else {
 
283
                /*
 
284
                 * If the current buffer size is bigger than the space needed,
 
285
                 * just double it, else add extra_space. Always keep 64 bytes
 
286
                 * more, so that after we added a large blob we don't have to
 
287
                 * realloc immediately again.
 
288
                 */
 
289
                new_size = MAX(ps->buffer_size*2,
 
290
                               ps->buffer_size + extra_space + 64);
 
291
 
 
292
                if ((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
 
293
                        DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
 
294
                                (unsigned int)new_size));
 
295
                        return False;
 
296
                }
 
297
 
 
298
                memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
 
299
        }
 
300
        ps->buffer_size = new_size;
 
301
 
 
302
        return True;
 
303
}
 
304
 
 
305
/*******************************************************************
 
306
 Attempt to force a data buffer to grow by len bytes.
 
307
 This is only used when appending more data onto a prs_struct
 
308
 when reading an rpc reply, before unmarshalling it.
 
309
 ********************************************************************/
 
310
 
 
311
bool prs_force_grow(prs_struct *ps, uint32 extra_space)
 
312
{
 
313
        uint32 new_size = ps->buffer_size + extra_space;
 
314
 
 
315
        if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
 
316
                DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
 
317
                                (unsigned int)extra_space));
 
318
                return False;
 
319
        }
 
320
 
 
321
        if((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
 
322
                DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
 
323
                        (unsigned int)new_size));
 
324
                return False;
 
325
        }
 
326
 
 
327
        memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
 
328
 
 
329
        ps->buffer_size = new_size;
 
330
 
 
331
        return True;
 
332
}
 
333
 
 
334
/*******************************************************************
 
335
 Get the data pointer (external interface).
 
336
********************************************************************/
 
337
 
 
338
char *prs_data_p(prs_struct *ps)
 
339
{
 
340
        return ps->data_p;
 
341
}
 
342
 
 
343
/*******************************************************************
 
344
 Get the current data size (external interface).
 
345
 ********************************************************************/
 
346
 
 
347
uint32 prs_data_size(prs_struct *ps)
 
348
{
 
349
        return ps->buffer_size;
 
350
}
 
351
 
 
352
/*******************************************************************
 
353
 Fetch the current offset (external interface).
 
354
 ********************************************************************/
 
355
 
 
356
uint32 prs_offset(prs_struct *ps)
 
357
{
 
358
        return ps->data_offset;
 
359
}
 
360
 
 
361
/*******************************************************************
 
362
 Set the current offset (external interface).
 
363
 ********************************************************************/
 
364
 
 
365
bool prs_set_offset(prs_struct *ps, uint32 offset)
 
366
{
 
367
        if ((offset > ps->data_offset)
 
368
            && !prs_grow(ps, offset - ps->data_offset)) {
 
369
                return False;
 
370
        }
 
371
 
 
372
        ps->data_offset = offset;
 
373
        return True;
 
374
}
 
375
 
 
376
/*******************************************************************
 
377
 Append the data from one parse_struct into another.
 
378
 ********************************************************************/
 
379
 
 
380
bool prs_append_prs_data(prs_struct *dst, prs_struct *src)
 
381
{
 
382
        if (prs_offset(src) == 0)
 
383
                return True;
 
384
 
 
385
        if(!prs_grow(dst, prs_offset(src)))
 
386
                return False;
 
387
 
 
388
        memcpy(&dst->data_p[dst->data_offset], src->data_p, (size_t)prs_offset(src));
 
389
        dst->data_offset += prs_offset(src);
 
390
 
 
391
        return True;
 
392
}
 
393
 
 
394
/*******************************************************************
 
395
 Append some data from one parse_struct into another.
 
396
 ********************************************************************/
 
397
 
 
398
bool prs_append_some_data(prs_struct *dst, void *src_base, uint32_t start,
 
399
                          uint32_t len)
 
400
{
 
401
        if (len == 0) {
 
402
                return true;
 
403
        }
 
404
 
 
405
        if(!prs_grow(dst, len)) {
 
406
                return false;
 
407
        }
 
408
 
 
409
        memcpy(&dst->data_p[dst->data_offset], ((char *)src_base) + start, (size_t)len);
 
410
        dst->data_offset += len;
 
411
        return true;
 
412
}
 
413
 
 
414
bool prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start,
 
415
                              uint32 len)
 
416
{
 
417
        return prs_append_some_data(dst, src->data_p, start, len);
 
418
}
 
419
 
 
420
/*******************************************************************
 
421
 Append the data from a buffer into a parse_struct.
 
422
 ********************************************************************/
 
423
 
 
424
bool prs_copy_data_in(prs_struct *dst, const char *src, uint32 len)
 
425
{
 
426
        if (len == 0)
 
427
                return True;
 
428
 
 
429
        if(!prs_grow(dst, len))
 
430
                return False;
 
431
 
 
432
        memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
 
433
        dst->data_offset += len;
 
434
 
 
435
        return True;
 
436
}
 
437
 
 
438
/*******************************************************************
 
439
 Copy some data from a parse_struct into a buffer.
 
440
 ********************************************************************/
 
441
 
 
442
bool prs_copy_data_out(char *dst, prs_struct *src, uint32 len)
 
443
{
 
444
        if (len == 0)
 
445
                return True;
 
446
 
 
447
        if(!prs_mem_get(src, len))
 
448
                return False;
 
449
 
 
450
        memcpy(dst, &src->data_p[src->data_offset], (size_t)len);
 
451
        src->data_offset += len;
 
452
 
 
453
        return True;
 
454
}
 
455
 
 
456
/*******************************************************************
 
457
 Copy all the data from a parse_struct into a buffer.
 
458
 ********************************************************************/
 
459
 
 
460
bool prs_copy_all_data_out(char *dst, prs_struct *src)
 
461
{
 
462
        uint32 len = prs_offset(src);
 
463
 
 
464
        if (!len)
 
465
                return True;
 
466
 
 
467
        prs_set_offset(src, 0);
 
468
        return prs_copy_data_out(dst, src, len);
 
469
}
 
470
 
 
471
/*******************************************************************
 
472
 Set the data as X-endian (external interface).
 
473
 ********************************************************************/
 
474
 
 
475
void prs_set_endian_data(prs_struct *ps, bool endian)
 
476
{
 
477
        ps->bigendian_data = endian;
 
478
}
 
479
 
 
480
/*******************************************************************
 
481
 Align a the data_len to a multiple of align bytes - filling with
 
482
 zeros.
 
483
 ********************************************************************/
 
484
 
 
485
bool prs_align(prs_struct *ps)
 
486
{
 
487
        uint32 mod = ps->data_offset & (ps->align-1);
 
488
 
 
489
        if (ps->align != 0 && mod != 0) {
 
490
                uint32 extra_space = (ps->align - mod);
 
491
                if(!prs_grow(ps, extra_space))
 
492
                        return False;
 
493
                memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
 
494
                ps->data_offset += extra_space;
 
495
        }
 
496
 
 
497
        return True;
 
498
}
 
499
 
 
500
/******************************************************************
 
501
 Align on a 2 byte boundary
 
502
 *****************************************************************/
 
503
 
 
504
bool prs_align_uint16(prs_struct *ps)
 
505
{
 
506
        bool ret;
 
507
        uint8 old_align = ps->align;
 
508
 
 
509
        ps->align = 2;
 
510
        ret = prs_align(ps);
 
511
        ps->align = old_align;
 
512
        
 
513
        return ret;
 
514
}
 
515
 
 
516
/******************************************************************
 
517
 Align on a 8 byte boundary
 
518
 *****************************************************************/
 
519
 
 
520
bool prs_align_uint64(prs_struct *ps)
 
521
{
 
522
        bool ret;
 
523
        uint8 old_align = ps->align;
 
524
 
 
525
        ps->align = 8;
 
526
        ret = prs_align(ps);
 
527
        ps->align = old_align;
 
528
        
 
529
        return ret;
 
530
}
 
531
 
 
532
/******************************************************************
 
533
 Align on a specific byte boundary
 
534
 *****************************************************************/
 
535
 
 
536
bool prs_align_custom(prs_struct *ps, uint8 boundary)
 
537
{
 
538
        bool ret;
 
539
        uint8 old_align = ps->align;
 
540
 
 
541
        ps->align = boundary;
 
542
        ret = prs_align(ps);
 
543
        ps->align = old_align;
 
544
        
 
545
        return ret;
 
546
}
 
547
 
 
548
 
 
549
 
 
550
/*******************************************************************
 
551
 Align only if required (for the unistr2 string mainly)
 
552
 ********************************************************************/
 
553
 
 
554
bool prs_align_needed(prs_struct *ps, uint32 needed)
 
555
{
 
556
        if (needed==0)
 
557
                return True;
 
558
        else
 
559
                return prs_align(ps);
 
560
}
 
561
 
 
562
/*******************************************************************
 
563
 Ensure we can read/write to a given offset.
 
564
 ********************************************************************/
 
565
 
 
566
char *prs_mem_get(prs_struct *ps, uint32 extra_size)
 
567
{
 
568
        if(UNMARSHALLING(ps)) {
 
569
                /*
 
570
                 * If reading, ensure that we can read the requested size item.
 
571
                 */
 
572
                if (ps->data_offset + extra_size > ps->buffer_size) {
 
573
                        DEBUG(0,("prs_mem_get: reading data of size %u would overrun "
 
574
                                "buffer by %u bytes.\n",
 
575
                                (unsigned int)extra_size,
 
576
                                (unsigned int)(ps->data_offset + extra_size - ps->buffer_size) ));
 
577
                        return NULL;
 
578
                }
 
579
        } else {
 
580
                /*
 
581
                 * Writing - grow the buffer if needed.
 
582
                 */
 
583
                if(!prs_grow(ps, extra_size))
 
584
                        return NULL;
 
585
        }
 
586
        return &ps->data_p[ps->data_offset];
 
587
}
 
588
 
 
589
/*******************************************************************
 
590
 Change the struct type.
 
591
 ********************************************************************/
 
592
 
 
593
void prs_switch_type(prs_struct *ps, bool io)
 
594
{
 
595
        if ((ps->io ^ io) == True)
 
596
                ps->io=io;
 
597
}
 
598
 
 
599
/*******************************************************************
 
600
 Force a prs_struct to be dynamic even when it's size is 0.
 
601
 ********************************************************************/
 
602
 
 
603
void prs_force_dynamic(prs_struct *ps)
 
604
{
 
605
        ps->is_dynamic=True;
 
606
}
 
607
 
 
608
/*******************************************************************
 
609
 Associate a session key with a parse struct.
 
610
 ********************************************************************/
 
611
 
 
612
void prs_set_session_key(prs_struct *ps, const char sess_key[16])
 
613
{
 
614
        ps->sess_key = sess_key;
 
615
}
 
616
 
 
617
/*******************************************************************
 
618
 Stream a uint8.
 
619
 ********************************************************************/
 
620
 
 
621
bool prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8)
 
622
{
 
623
        char *q = prs_mem_get(ps, 1);
 
624
        if (q == NULL)
 
625
                return False;
 
626
 
 
627
        if (UNMARSHALLING(ps))
 
628
                *data8 = CVAL(q,0);
 
629
        else
 
630
                SCVAL(q,0,*data8);
 
631
 
 
632
        DEBUGADD(5,("%s%04x %s: %02x\n", tab_depth(5,depth), ps->data_offset, name, *data8));
 
633
 
 
634
        ps->data_offset += 1;
 
635
 
 
636
        return True;
 
637
}
 
638
 
 
639
/*******************************************************************
 
640
 Stream a uint16* (allocate memory if unmarshalling)
 
641
 ********************************************************************/
 
642
 
 
643
bool prs_pointer( const char *name, prs_struct *ps, int depth, 
 
644
                 void *dta, size_t data_size,
 
645
                 bool (*prs_fn)(const char*, prs_struct*, int, void*) )
 
646
{
 
647
        void ** data = (void **)dta;
 
648
        uint32 data_p;
 
649
 
 
650
        /* output f000baaa to stream if the pointer is non-zero. */
 
651
 
 
652
        data_p = *data ? 0xf000baaa : 0;
 
653
 
 
654
        if ( !prs_uint32("ptr", ps, depth, &data_p ))
 
655
                return False;
 
656
 
 
657
        /* we're done if there is no data */
 
658
 
 
659
        if ( !data_p )
 
660
                return True;
 
661
 
 
662
        if (UNMARSHALLING(ps)) {
 
663
                if (data_size) {
 
664
                        if ( !(*data = PRS_ALLOC_MEM(ps, char, data_size)) )
 
665
                                return False;
 
666
                } else {
 
667
                        *data = NULL;
 
668
                }
 
669
        }
 
670
 
 
671
        return prs_fn(name, ps, depth, *data);
 
672
}
 
673
 
 
674
 
 
675
/*******************************************************************
 
676
 Stream a uint16.
 
677
 ********************************************************************/
 
678
 
 
679
bool prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16)
 
680
{
 
681
        char *q = prs_mem_get(ps, sizeof(uint16));
 
682
        if (q == NULL)
 
683
                return False;
 
684
 
 
685
        if (UNMARSHALLING(ps)) {
 
686
                if (ps->bigendian_data)
 
687
                        *data16 = RSVAL(q,0);
 
688
                else
 
689
                        *data16 = SVAL(q,0);
 
690
        } else {
 
691
                if (ps->bigendian_data)
 
692
                        RSSVAL(q,0,*data16);
 
693
                else
 
694
                        SSVAL(q,0,*data16);
 
695
        }
 
696
 
 
697
        DEBUGADD(5,("%s%04x %s: %04x\n", tab_depth(5,depth), ps->data_offset, name, *data16));
 
698
 
 
699
        ps->data_offset += sizeof(uint16);
 
700
 
 
701
        return True;
 
702
}
 
703
 
 
704
/*******************************************************************
 
705
 Stream a uint32.
 
706
 ********************************************************************/
 
707
 
 
708
bool prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32)
 
709
{
 
710
        char *q = prs_mem_get(ps, sizeof(uint32));
 
711
        if (q == NULL)
 
712
                return False;
 
713
 
 
714
        if (UNMARSHALLING(ps)) {
 
715
                if (ps->bigendian_data)
 
716
                        *data32 = RIVAL(q,0);
 
717
                else
 
718
                        *data32 = IVAL(q,0);
 
719
        } else {
 
720
                if (ps->bigendian_data)
 
721
                        RSIVAL(q,0,*data32);
 
722
                else
 
723
                        SIVAL(q,0,*data32);
 
724
        }
 
725
 
 
726
        DEBUGADD(5,("%s%04x %s: %08x\n", tab_depth(5,depth), ps->data_offset, name, *data32));
 
727
 
 
728
        ps->data_offset += sizeof(uint32);
 
729
 
 
730
        return True;
 
731
}
 
732
 
 
733
/*******************************************************************
 
734
 Stream an int32.
 
735
 ********************************************************************/
 
736
 
 
737
bool prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32)
 
738
{
 
739
        char *q = prs_mem_get(ps, sizeof(int32));
 
740
        if (q == NULL)
 
741
                return False;
 
742
 
 
743
        if (UNMARSHALLING(ps)) {
 
744
                if (ps->bigendian_data)
 
745
                        *data32 = RIVALS(q,0);
 
746
                else
 
747
                        *data32 = IVALS(q,0);
 
748
        } else {
 
749
                if (ps->bigendian_data)
 
750
                        RSIVALS(q,0,*data32);
 
751
                else
 
752
                        SIVALS(q,0,*data32);
 
753
        }
 
754
 
 
755
        DEBUGADD(5,("%s%04x %s: %08x\n", tab_depth(5,depth), ps->data_offset, name, *data32));
 
756
 
 
757
        ps->data_offset += sizeof(int32);
 
758
 
 
759
        return True;
 
760
}
 
761
 
 
762
/*******************************************************************
 
763
 Stream a uint64_struct
 
764
 ********************************************************************/
 
765
bool prs_uint64(const char *name, prs_struct *ps, int depth, uint64 *data64)
 
766
{
 
767
        if (UNMARSHALLING(ps)) {
 
768
                uint32 high, low;
 
769
 
 
770
                if (!prs_uint32(name, ps, depth+1, &low))
 
771
                        return False;
 
772
 
 
773
                if (!prs_uint32(name, ps, depth+1, &high))
 
774
                        return False;
 
775
 
 
776
                *data64 = ((uint64_t)high << 32) + low;
 
777
 
 
778
                return True;
 
779
        } else {
 
780
                uint32 high = (*data64) >> 32, low = (*data64) & 0xFFFFFFFF;
 
781
                return prs_uint32(name, ps, depth+1, &low) &&
 
782
                           prs_uint32(name, ps, depth+1, &high);
 
783
        }
 
784
}
 
785
 
 
786
/*******************************************************************
 
787
 Stream a NTSTATUS
 
788
 ********************************************************************/
 
789
 
 
790
bool prs_ntstatus(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
 
791
{
 
792
        char *q = prs_mem_get(ps, sizeof(uint32));
 
793
        if (q == NULL)
 
794
                return False;
 
795
 
 
796
        if (UNMARSHALLING(ps)) {
 
797
                if (ps->bigendian_data)
 
798
                        *status = NT_STATUS(RIVAL(q,0));
 
799
                else
 
800
                        *status = NT_STATUS(IVAL(q,0));
 
801
        } else {
 
802
                if (ps->bigendian_data)
 
803
                        RSIVAL(q,0,NT_STATUS_V(*status));
 
804
                else
 
805
                        SIVAL(q,0,NT_STATUS_V(*status));
 
806
        }
 
807
 
 
808
        DEBUGADD(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
 
809
                 nt_errstr(*status)));
 
810
 
 
811
        ps->data_offset += sizeof(uint32);
 
812
 
 
813
        return True;
 
814
}
 
815
 
 
816
/*******************************************************************
 
817
 Stream a DCE error code
 
818
 ********************************************************************/
 
819
 
 
820
bool prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
 
821
{
 
822
        char *q = prs_mem_get(ps, sizeof(uint32));
 
823
        if (q == NULL)
 
824
                return False;
 
825
 
 
826
        if (UNMARSHALLING(ps)) {
 
827
                if (ps->bigendian_data)
 
828
                        *status = NT_STATUS(RIVAL(q,0));
 
829
                else
 
830
                        *status = NT_STATUS(IVAL(q,0));
 
831
        } else {
 
832
                if (ps->bigendian_data)
 
833
                        RSIVAL(q,0,NT_STATUS_V(*status));
 
834
                else
 
835
                        SIVAL(q,0,NT_STATUS_V(*status));
 
836
        }
 
837
 
 
838
        DEBUGADD(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
 
839
                 dcerpc_errstr(debug_ctx(), NT_STATUS_V(*status))));
 
840
 
 
841
        ps->data_offset += sizeof(uint32);
 
842
 
 
843
        return True;
 
844
}
 
845
 
 
846
 
 
847
/*******************************************************************
 
848
 Stream a WERROR
 
849
 ********************************************************************/
 
850
 
 
851
bool prs_werror(const char *name, prs_struct *ps, int depth, WERROR *status)
 
852
{
 
853
        char *q = prs_mem_get(ps, sizeof(uint32));
 
854
        if (q == NULL)
 
855
                return False;
 
856
 
 
857
        if (UNMARSHALLING(ps)) {
 
858
                if (ps->bigendian_data)
 
859
                        *status = W_ERROR(RIVAL(q,0));
 
860
                else
 
861
                        *status = W_ERROR(IVAL(q,0));
 
862
        } else {
 
863
                if (ps->bigendian_data)
 
864
                        RSIVAL(q,0,W_ERROR_V(*status));
 
865
                else
 
866
                        SIVAL(q,0,W_ERROR_V(*status));
 
867
        }
 
868
 
 
869
        DEBUGADD(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
 
870
                 win_errstr(*status)));
 
871
 
 
872
        ps->data_offset += sizeof(uint32);
 
873
 
 
874
        return True;
 
875
}
 
876
 
 
877
 
 
878
/******************************************************************
 
879
 Stream an array of uint8s. Length is number of uint8s.
 
880
 ********************************************************************/
 
881
 
 
882
bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
 
883
{
 
884
        int i;
 
885
        char *q = prs_mem_get(ps, len);
 
886
        if (q == NULL)
 
887
                return False;
 
888
 
 
889
        if (UNMARSHALLING(ps)) {
 
890
                for (i = 0; i < len; i++)
 
891
                        data8s[i] = CVAL(q,i);
 
892
        } else {
 
893
                for (i = 0; i < len; i++)
 
894
                        SCVAL(q, i, data8s[i]);
 
895
        }
 
896
 
 
897
        DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset ,name));
 
898
        if (charmode)
 
899
                print_asc(5, (unsigned char*)data8s, len);
 
900
        else {
 
901
                for (i = 0; i < len; i++)
 
902
                        DEBUGADD(5,("%02x ", data8s[i]));
 
903
        }
 
904
        DEBUGADD(5,("\n"));
 
905
 
 
906
        ps->data_offset += len;
 
907
 
 
908
        return True;
 
909
}
 
910
 
 
911
/******************************************************************
 
912
 Stream an array of uint16s. Length is number of uint16s.
 
913
 ********************************************************************/
 
914
 
 
915
bool prs_uint16s(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
 
916
{
 
917
        int i;
 
918
        char *q = prs_mem_get(ps, len * sizeof(uint16));
 
919
        if (q == NULL)
 
920
                return False;
 
921
 
 
922
        if (UNMARSHALLING(ps)) {
 
923
                if (ps->bigendian_data) {
 
924
                        for (i = 0; i < len; i++)
 
925
                                data16s[i] = RSVAL(q, 2*i);
 
926
                } else {
 
927
                        for (i = 0; i < len; i++)
 
928
                                data16s[i] = SVAL(q, 2*i);
 
929
                }
 
930
        } else {
 
931
                if (ps->bigendian_data) {
 
932
                        for (i = 0; i < len; i++)
 
933
                                RSSVAL(q, 2*i, data16s[i]);
 
934
                } else {
 
935
                        for (i = 0; i < len; i++)
 
936
                                SSVAL(q, 2*i, data16s[i]);
 
937
                }
 
938
        }
 
939
 
 
940
        DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
 
941
        if (charmode)
 
942
                print_asc(5, (unsigned char*)data16s, 2*len);
 
943
        else {
 
944
                for (i = 0; i < len; i++)
 
945
                        DEBUGADD(5,("%04x ", data16s[i]));
 
946
        }
 
947
        DEBUGADD(5,("\n"));
 
948
 
 
949
        ps->data_offset += (len * sizeof(uint16));
 
950
 
 
951
        return True;
 
952
}
 
953
 
 
954
/******************************************************************
 
955
 Start using a function for streaming unicode chars. If unmarshalling,
 
956
 output must be little-endian, if marshalling, input must be little-endian.
 
957
 ********************************************************************/
 
958
 
 
959
static void dbg_rw_punival(bool charmode, const char *name, int depth, prs_struct *ps,
 
960
                                                        char *in_buf, char *out_buf, int len)
 
961
{
 
962
        int i;
 
963
 
 
964
        if (UNMARSHALLING(ps)) {
 
965
                if (ps->bigendian_data) {
 
966
                        for (i = 0; i < len; i++)
 
967
                                SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i));
 
968
                } else {
 
969
                        for (i = 0; i < len; i++)
 
970
                                SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i));
 
971
                }
 
972
        } else {
 
973
                if (ps->bigendian_data) {
 
974
                        for (i = 0; i < len; i++)
 
975
                                RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
 
976
                } else {
 
977
                        for (i = 0; i < len; i++)
 
978
                                SSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
 
979
                }
 
980
        }
 
981
 
 
982
        DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
 
983
        if (charmode)
 
984
                print_asc(5, (unsigned char*)out_buf, 2*len);
 
985
        else {
 
986
                for (i = 0; i < len; i++)
 
987
                        DEBUGADD(5,("%04x ", out_buf[i]));
 
988
        }
 
989
        DEBUGADD(5,("\n"));
 
990
}
 
991
 
 
992
/******************************************************************
 
993
 Stream a unistr. Always little endian.
 
994
 ********************************************************************/
 
995
 
 
996
bool prs_uint16uni(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
 
997
{
 
998
        char *q = prs_mem_get(ps, len * sizeof(uint16));
 
999
        if (q == NULL)
 
1000
                return False;
 
1001
 
 
1002
        dbg_rw_punival(charmode, name, depth, ps, q, (char *)data16s, len);
 
1003
        ps->data_offset += (len * sizeof(uint16));
 
1004
 
 
1005
        return True;
 
1006
}
 
1007
 
 
1008
/******************************************************************
 
1009
 Stream an array of uint32s. Length is number of uint32s.
 
1010
 ********************************************************************/
 
1011
 
 
1012
bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
 
1013
{
 
1014
        int i;
 
1015
        char *q = prs_mem_get(ps, len * sizeof(uint32));
 
1016
        if (q == NULL)
 
1017
                return False;
 
1018
 
 
1019
        if (UNMARSHALLING(ps)) {
 
1020
                if (ps->bigendian_data) {
 
1021
                        for (i = 0; i < len; i++)
 
1022
                                data32s[i] = RIVAL(q, 4*i);
 
1023
                } else {
 
1024
                        for (i = 0; i < len; i++)
 
1025
                                data32s[i] = IVAL(q, 4*i);
 
1026
                }
 
1027
        } else {
 
1028
                if (ps->bigendian_data) {
 
1029
                        for (i = 0; i < len; i++)
 
1030
                                RSIVAL(q, 4*i, data32s[i]);
 
1031
                } else {
 
1032
                        for (i = 0; i < len; i++)
 
1033
                                SIVAL(q, 4*i, data32s[i]);
 
1034
                }
 
1035
        }
 
1036
 
 
1037
        DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
 
1038
        if (charmode)
 
1039
                print_asc(5, (unsigned char*)data32s, 4*len);
 
1040
        else {
 
1041
                for (i = 0; i < len; i++)
 
1042
                        DEBUGADD(5,("%08x ", data32s[i]));
 
1043
        }
 
1044
        DEBUGADD(5,("\n"));
 
1045
 
 
1046
        ps->data_offset += (len * sizeof(uint32));
 
1047
 
 
1048
        return True;
 
1049
}
 
1050
 
 
1051
/*******************************************************************
 
1052
 Stream a unicode  null-terminated string. As the string is already
 
1053
 in little-endian format then do it as a stream of bytes.
 
1054
 ********************************************************************/
 
1055
 
 
1056
bool prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str)
 
1057
{
 
1058
        unsigned int len = 0;
 
1059
        unsigned char *p = (unsigned char *)str->buffer;
 
1060
        uint8 *start;
 
1061
        char *q;
 
1062
        uint32 max_len;
 
1063
        uint16* ptr;
 
1064
 
 
1065
        if (MARSHALLING(ps)) {
 
1066
 
 
1067
                for(len = 0; str->buffer[len] != 0; len++)
 
1068
                        ;
 
1069
 
 
1070
                q = prs_mem_get(ps, (len+1)*2);
 
1071
                if (q == NULL)
 
1072
                        return False;
 
1073
 
 
1074
                start = (uint8*)q;
 
1075
 
 
1076
                for(len = 0; str->buffer[len] != 0; len++) {
 
1077
                        if(ps->bigendian_data) {
 
1078
                                /* swap bytes - p is little endian, q is big endian. */
 
1079
                                q[0] = (char)p[1];
 
1080
                                q[1] = (char)p[0];
 
1081
                                p += 2;
 
1082
                                q += 2;
 
1083
                        } 
 
1084
                        else 
 
1085
                        {
 
1086
                                q[0] = (char)p[0];
 
1087
                                q[1] = (char)p[1];
 
1088
                                p += 2;
 
1089
                                q += 2;
 
1090
                        }
 
1091
                }
 
1092
 
 
1093
                /*
 
1094
                 * even if the string is 'empty' (only an \0 char)
 
1095
                 * at this point the leading \0 hasn't been parsed.
 
1096
                 * so parse it now
 
1097
                 */
 
1098
 
 
1099
                q[0] = 0;
 
1100
                q[1] = 0;
 
1101
                q += 2;
 
1102
 
 
1103
                len++;
 
1104
 
 
1105
                DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
 
1106
                print_asc(5, (unsigned char*)start, 2*len);     
 
1107
                DEBUGADD(5, ("\n"));
 
1108
        }
 
1109
        else { /* unmarshalling */
 
1110
        
 
1111
                uint32 alloc_len = 0;
 
1112
                q = ps->data_p + prs_offset(ps);
 
1113
 
 
1114
                /*
 
1115
                 * Work out how much space we need and talloc it.
 
1116
                 */
 
1117
                max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16);
 
1118
 
 
1119
                /* the test of the value of *ptr helps to catch the circumstance
 
1120
                   where we have an emtpty (non-existent) string in the buffer */
 
1121
                for ( ptr = (uint16 *)q; *ptr++ && (alloc_len <= max_len); alloc_len++)
 
1122
                        /* do nothing */ 
 
1123
                        ;
 
1124
 
 
1125
                if (alloc_len < max_len)
 
1126
                        alloc_len += 1;
 
1127
 
 
1128
                /* should we allocate anything at all? */
 
1129
                str->buffer = PRS_ALLOC_MEM(ps,uint16,alloc_len);
 
1130
                if ((str->buffer == NULL) && (alloc_len > 0))
 
1131
                        return False;
 
1132
 
 
1133
                p = (unsigned char *)str->buffer;
 
1134
 
 
1135
                len = 0;
 
1136
                /* the (len < alloc_len) test is to prevent us from overwriting
 
1137
                   memory that is not ours...if we get that far, we have a non-null
 
1138
                   terminated string in the buffer and have messed up somewhere */
 
1139
                while ((len < alloc_len) && (*(uint16 *)q != 0)) {
 
1140
                        if(ps->bigendian_data) 
 
1141
                        {
 
1142
                                /* swap bytes - q is big endian, p is little endian. */
 
1143
                                p[0] = (unsigned char)q[1];
 
1144
                                p[1] = (unsigned char)q[0];
 
1145
                                p += 2;
 
1146
                                q += 2;
 
1147
                        } else {
 
1148
 
 
1149
                                p[0] = (unsigned char)q[0];
 
1150
                                p[1] = (unsigned char)q[1];
 
1151
                                p += 2;
 
1152
                                q += 2;
 
1153
                        }
 
1154
 
 
1155
                        len++;
 
1156
                } 
 
1157
                if (len < alloc_len) {
 
1158
                        /* NULL terminate the UNISTR */
 
1159
                        str->buffer[len++] = '\0';
 
1160
                }
 
1161
 
 
1162
                DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
 
1163
                print_asc(5, (unsigned char*)str->buffer, 2*len);       
 
1164
                DEBUGADD(5, ("\n"));
 
1165
        }
 
1166
 
 
1167
        /* set the offset in the prs_struct; 'len' points to the
 
1168
           terminiating NULL in the UNISTR so we need to go one more
 
1169
           uint16 */
 
1170
        ps->data_offset += (len)*2;
 
1171
        
 
1172
        return True;
 
1173
}
 
1174
 
 
1175
 
 
1176
/*******************************************************************
 
1177
 Stream a null-terminated string.  len is strlen, and therefore does
 
1178
 not include the null-termination character.
 
1179
 ********************************************************************/
 
1180
 
 
1181
bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size)
 
1182
{
 
1183
        char *q;
 
1184
        int i;
 
1185
        int len;
 
1186
 
 
1187
        if (UNMARSHALLING(ps))
 
1188
                len = strlen(&ps->data_p[ps->data_offset]);
 
1189
        else
 
1190
                len = strlen(str);
 
1191
 
 
1192
        len = MIN(len, (max_buf_size-1));
 
1193
 
 
1194
        q = prs_mem_get(ps, len+1);
 
1195
        if (q == NULL)
 
1196
                return False;
 
1197
 
 
1198
        for(i = 0; i < len; i++) {
 
1199
                if (UNMARSHALLING(ps))
 
1200
                        str[i] = q[i];
 
1201
                else
 
1202
                        q[i] = str[i];
 
1203
        }
 
1204
 
 
1205
        /* The terminating null. */
 
1206
        str[i] = '\0';
 
1207
 
 
1208
        if (MARSHALLING(ps)) {
 
1209
                q[i] = '\0';
 
1210
        }
 
1211
 
 
1212
        ps->data_offset += len+1;
 
1213
 
 
1214
        dump_data(5+depth, (uint8 *)q, len);
 
1215
 
 
1216
        return True;
 
1217
}
 
1218
 
 
1219
bool prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str)
 
1220
{
 
1221
        size_t len;
 
1222
        char *tmp_str;
 
1223
 
 
1224
        if (UNMARSHALLING(ps)) {
 
1225
                len = strlen(&ps->data_p[ps->data_offset]);
 
1226
        } else {
 
1227
                len = strlen(*str);
 
1228
        }
 
1229
 
 
1230
        tmp_str = PRS_ALLOC_MEM(ps, char, len+1);
 
1231
 
 
1232
        if (tmp_str == NULL) {
 
1233
                return False;
 
1234
        }
 
1235
 
 
1236
        if (MARSHALLING(ps)) {
 
1237
                strncpy(tmp_str, *str, len);
 
1238
        }
 
1239
 
 
1240
        if (!prs_string(name, ps, depth, tmp_str, len+1)) {
 
1241
                return False;
 
1242
        }
 
1243
 
 
1244
        *str = tmp_str;
 
1245
        return True;
 
1246
}
 
1247
 
 
1248
/*******************************************************************
 
1249
 prs_uint16 wrapper. Call this and it sets up a pointer to where the
 
1250
 uint16 should be stored, or gets the size if reading.
 
1251
 ********************************************************************/
 
1252
 
 
1253
bool prs_uint16_pre(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
 
1254
{
 
1255
        *offset = ps->data_offset;
 
1256
        if (UNMARSHALLING(ps)) {
 
1257
                /* reading. */
 
1258
                return prs_uint16(name, ps, depth, data16);
 
1259
        } else {
 
1260
                char *q = prs_mem_get(ps, sizeof(uint16));
 
1261
                if(q ==NULL)
 
1262
                        return False;
 
1263
                ps->data_offset += sizeof(uint16);
 
1264
        }
 
1265
        return True;
 
1266
}
 
1267
 
 
1268
/*******************************************************************
 
1269
 prs_uint16 wrapper.  call this and it retrospectively stores the size.
 
1270
 does nothing on reading, as that is already handled by ...._pre()
 
1271
 ********************************************************************/
 
1272
 
 
1273
bool prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16,
 
1274
                                uint32 ptr_uint16, uint32 start_offset)
 
1275
{
 
1276
        if (MARSHALLING(ps)) {
 
1277
                /* 
 
1278
                 * Writing - temporarily move the offset pointer.
 
1279
                 */
 
1280
                uint16 data_size = ps->data_offset - start_offset;
 
1281
                uint32 old_offset = ps->data_offset;
 
1282
 
 
1283
                ps->data_offset = ptr_uint16;
 
1284
                if(!prs_uint16(name, ps, depth, &data_size)) {
 
1285
                        ps->data_offset = old_offset;
 
1286
                        return False;
 
1287
                }
 
1288
                ps->data_offset = old_offset;
 
1289
        } else {
 
1290
                ps->data_offset = start_offset + (uint32)(*data16);
 
1291
        }
 
1292
        return True;
 
1293
}
 
1294
 
 
1295
/*******************************************************************
 
1296
 prs_uint32 wrapper. Call this and it sets up a pointer to where the
 
1297
 uint32 should be stored, or gets the size if reading.
 
1298
 ********************************************************************/
 
1299
 
 
1300
bool prs_uint32_pre(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
 
1301
{
 
1302
        *offset = ps->data_offset;
 
1303
        if (UNMARSHALLING(ps) && (data32 != NULL)) {
 
1304
                /* reading. */
 
1305
                return prs_uint32(name, ps, depth, data32);
 
1306
        } else {
 
1307
                ps->data_offset += sizeof(uint32);
 
1308
        }
 
1309
        return True;
 
1310
}
 
1311
 
 
1312
/*******************************************************************
 
1313
 prs_uint32 wrapper.  call this and it retrospectively stores the size.
 
1314
 does nothing on reading, as that is already handled by ...._pre()
 
1315
 ********************************************************************/
 
1316
 
 
1317
bool prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32,
 
1318
                                uint32 ptr_uint32, uint32 data_size)
 
1319
{
 
1320
        if (MARSHALLING(ps)) {
 
1321
                /* 
 
1322
                 * Writing - temporarily move the offset pointer.
 
1323
                 */
 
1324
                uint32 old_offset = ps->data_offset;
 
1325
                ps->data_offset = ptr_uint32;
 
1326
                if(!prs_uint32(name, ps, depth, &data_size)) {
 
1327
                        ps->data_offset = old_offset;
 
1328
                        return False;
 
1329
                }
 
1330
                ps->data_offset = old_offset;
 
1331
        }
 
1332
        return True;
 
1333
}
 
1334
 
 
1335
/* useful function to store a structure in rpc wire format */
 
1336
int tdb_prs_store(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps)
 
1337
{
 
1338
        TDB_DATA dbuf;
 
1339
        dbuf.dptr = (uint8 *)ps->data_p;
 
1340
        dbuf.dsize = prs_offset(ps);
 
1341
        return tdb_trans_store(tdb, kbuf, dbuf, TDB_REPLACE);
 
1342
}
 
1343
 
 
1344
/* useful function to fetch a structure into rpc wire format */
 
1345
int tdb_prs_fetch(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps, TALLOC_CTX *mem_ctx)
 
1346
{
 
1347
        TDB_DATA dbuf;
 
1348
 
 
1349
        prs_init_empty(ps, mem_ctx, UNMARSHALL);
 
1350
 
 
1351
        dbuf = tdb_fetch(tdb, kbuf);
 
1352
        if (!dbuf.dptr)
 
1353
                return -1;
 
1354
 
 
1355
        prs_give_memory(ps, (char *)dbuf.dptr, dbuf.dsize, True);
 
1356
 
 
1357
        return 0;
 
1358
}
 
1359
 
 
1360
/*******************************************************************
 
1361
 hash a stream.
 
1362
 ********************************************************************/
 
1363
 
 
1364
bool prs_hash1(prs_struct *ps, uint32 offset, int len)
 
1365
{
 
1366
        char *q;
 
1367
 
 
1368
        q = ps->data_p;
 
1369
        q = &q[offset];
 
1370
 
 
1371
#ifdef DEBUG_PASSWORD
 
1372
        DEBUG(100, ("prs_hash1\n"));
 
1373
        dump_data(100, (uint8 *)ps->sess_key, 16);
 
1374
        dump_data(100, (uint8 *)q, len);
 
1375
#endif
 
1376
        SamOEMhash((uchar *) q, (const unsigned char *)ps->sess_key, len);
 
1377
 
 
1378
#ifdef DEBUG_PASSWORD
 
1379
        dump_data(100, (uint8 *)q, len);
 
1380
#endif
 
1381
 
 
1382
        return True;
 
1383
}
 
1384
 
 
1385
/*******************************************************************
 
1386
 Create a digest over the entire packet (including the data), and 
 
1387
 MD5 it with the session key.
 
1388
 ********************************************************************/
 
1389
 
 
1390
static void schannel_digest(struct schannel_auth_struct *a,
 
1391
                          enum pipe_auth_level auth_level,
 
1392
                          RPC_AUTH_SCHANNEL_CHK * verf,
 
1393
                          char *data, size_t data_len,
 
1394
                          uchar digest_final[16]) 
 
1395
{
 
1396
        uchar whole_packet_digest[16];
 
1397
        uchar zeros[4];
 
1398
        struct MD5Context ctx3;
 
1399
 
 
1400
        ZERO_STRUCT(zeros);
 
1401
 
 
1402
        /* verfiy the signature on the packet by MD5 over various bits */
 
1403
        MD5Init(&ctx3);
 
1404
        /* use our sequence number, which ensures the packet is not
 
1405
           out of order */
 
1406
        MD5Update(&ctx3, zeros, sizeof(zeros));
 
1407
        MD5Update(&ctx3, verf->sig, sizeof(verf->sig));
 
1408
        if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
 
1409
                MD5Update(&ctx3, verf->confounder, sizeof(verf->confounder));
 
1410
        }
 
1411
        MD5Update(&ctx3, (const unsigned char *)data, data_len);
 
1412
        MD5Final(whole_packet_digest, &ctx3);
 
1413
        dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest));
 
1414
        
 
1415
        /* MD5 this result and the session key, to prove that
 
1416
           only a valid client could had produced this */
 
1417
        hmac_md5(a->sess_key, whole_packet_digest, sizeof(whole_packet_digest), digest_final);
 
1418
}
 
1419
 
 
1420
/*******************************************************************
 
1421
 Calculate the key with which to encode the data payload 
 
1422
 ********************************************************************/
 
1423
 
 
1424
static void schannel_get_sealing_key(struct schannel_auth_struct *a,
 
1425
                                   RPC_AUTH_SCHANNEL_CHK *verf,
 
1426
                                   uchar sealing_key[16]) 
 
1427
{
 
1428
        uchar zeros[4];
 
1429
        uchar digest2[16];
 
1430
        uchar sess_kf0[16];
 
1431
        int i;
 
1432
 
 
1433
        ZERO_STRUCT(zeros);
 
1434
 
 
1435
        for (i = 0; i < sizeof(sess_kf0); i++) {
 
1436
                sess_kf0[i] = a->sess_key[i] ^ 0xf0;
 
1437
        }
 
1438
        
 
1439
        dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
 
1440
        
 
1441
        /* MD5 of sess_kf0 and 4 zero bytes */
 
1442
        hmac_md5(sess_kf0, zeros, 0x4, digest2);
 
1443
        dump_data_pw("digest2:\n", digest2, sizeof(digest2));
 
1444
        
 
1445
        /* MD5 of the above result, plus 8 bytes of sequence number */
 
1446
        hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key);
 
1447
        dump_data_pw("sealing_key:\n", sealing_key, 16);
 
1448
}
 
1449
 
 
1450
/*******************************************************************
 
1451
 Encode or Decode the sequence number (which is symmetric)
 
1452
 ********************************************************************/
 
1453
 
 
1454
static void schannel_deal_with_seq_num(struct schannel_auth_struct *a,
 
1455
                                     RPC_AUTH_SCHANNEL_CHK *verf)
 
1456
{
 
1457
        uchar zeros[4];
 
1458
        uchar sequence_key[16];
 
1459
        uchar digest1[16];
 
1460
 
 
1461
        ZERO_STRUCT(zeros);
 
1462
 
 
1463
        hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1);
 
1464
        dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1));
 
1465
 
 
1466
        hmac_md5(digest1, verf->packet_digest, 8, sequence_key);
 
1467
 
 
1468
        dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key));
 
1469
 
 
1470
        dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num));
 
1471
        SamOEMhash(verf->seq_num, sequence_key, 8);
 
1472
        dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num));
 
1473
}
 
1474
 
 
1475
/*******************************************************************
 
1476
creates an RPC_AUTH_SCHANNEL_CHK structure.
 
1477
********************************************************************/
 
1478
 
 
1479
static bool init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk,
 
1480
                              const uchar sig[8],
 
1481
                              const uchar packet_digest[8],
 
1482
                              const uchar seq_num[8], const uchar confounder[8])
 
1483
{
 
1484
        if (chk == NULL)
 
1485
                return False;
 
1486
 
 
1487
        memcpy(chk->sig, sig, sizeof(chk->sig));
 
1488
        memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest));
 
1489
        memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num));
 
1490
        memcpy(chk->confounder, confounder, sizeof(chk->confounder));
 
1491
 
 
1492
        return True;
 
1493
}
 
1494
 
 
1495
/*******************************************************************
 
1496
 Encode a blob of data using the schannel alogrithm, also produceing
 
1497
 a checksum over the original data.  We currently only support
 
1498
 signing and sealing togeather - the signing-only code is close, but not
 
1499
 quite compatible with what MS does.
 
1500
 ********************************************************************/
 
1501
 
 
1502
void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
 
1503
                   enum schannel_direction direction,
 
1504
                   RPC_AUTH_SCHANNEL_CHK * verf,
 
1505
                   char *data, size_t data_len)
 
1506
{
 
1507
        uchar digest_final[16];
 
1508
        uchar confounder[8];
 
1509
        uchar seq_num[8];
 
1510
        static const uchar nullbytes[8] = { 0, };
 
1511
 
 
1512
        static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
 
1513
        static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
 
1514
        const uchar *schannel_sig = NULL;
 
1515
 
 
1516
        DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
 
1517
        
 
1518
        if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
 
1519
                schannel_sig = schannel_seal_sig;
 
1520
        } else {
 
1521
                schannel_sig = schannel_sign_sig;
 
1522
        }
 
1523
 
 
1524
        /* fill the 'confounder' with random data */
 
1525
        generate_random_buffer(confounder, sizeof(confounder));
 
1526
 
 
1527
        dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
 
1528
 
 
1529
        RSIVAL(seq_num, 0, a->seq_num);
 
1530
 
 
1531
        switch (direction) {
 
1532
        case SENDER_IS_INITIATOR:
 
1533
                SIVAL(seq_num, 4, 0x80);
 
1534
                break;
 
1535
        case SENDER_IS_ACCEPTOR:
 
1536
                SIVAL(seq_num, 4, 0x0);
 
1537
                break;
 
1538
        }
 
1539
 
 
1540
        dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num));
 
1541
 
 
1542
        init_rpc_auth_schannel_chk(verf, schannel_sig, nullbytes,
 
1543
                                 seq_num, confounder);
 
1544
                                
 
1545
        /* produce a digest of the packet to prove it's legit (before we seal it) */
 
1546
        schannel_digest(a, auth_level, verf, data, data_len, digest_final);
 
1547
        memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest));
 
1548
 
 
1549
        if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
 
1550
                uchar sealing_key[16];
 
1551
 
 
1552
                /* get the key to encode the data with */
 
1553
                schannel_get_sealing_key(a, verf, sealing_key);
 
1554
 
 
1555
                /* encode the verification data */
 
1556
                dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder));
 
1557
                SamOEMhash(verf->confounder, sealing_key, 8);
 
1558
 
 
1559
                dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder));
 
1560
                
 
1561
                /* encode the packet payload */
 
1562
                dump_data_pw("data:\n", (const unsigned char *)data, data_len);
 
1563
                SamOEMhash((unsigned char *)data, sealing_key, data_len);
 
1564
                dump_data_pw("data_enc:\n", (const unsigned char *)data, data_len);
 
1565
        }
 
1566
 
 
1567
        /* encode the sequence number (key based on packet digest) */
 
1568
        /* needs to be done after the sealing, as the original version 
 
1569
           is used in the sealing stuff... */
 
1570
        schannel_deal_with_seq_num(a, verf);
 
1571
 
 
1572
        return;
 
1573
}
 
1574
 
 
1575
/*******************************************************************
 
1576
 Decode a blob of data using the schannel alogrithm, also verifiying
 
1577
 a checksum over the original data.  We currently can verify signed messages,
 
1578
 as well as decode sealed messages
 
1579
 ********************************************************************/
 
1580
 
 
1581
bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
 
1582
                   enum schannel_direction direction, 
 
1583
                   RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len)
 
1584
{
 
1585
        uchar digest_final[16];
 
1586
 
 
1587
        static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
 
1588
        static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
 
1589
        const uchar *schannel_sig = NULL;
 
1590
 
 
1591
        uchar seq_num[8];
 
1592
 
 
1593
        DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
 
1594
        
 
1595
        if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
 
1596
                schannel_sig = schannel_seal_sig;
 
1597
        } else {
 
1598
                schannel_sig = schannel_sign_sig;
 
1599
        }
 
1600
 
 
1601
        /* Create the expected sequence number for comparison */
 
1602
        RSIVAL(seq_num, 0, a->seq_num);
 
1603
 
 
1604
        switch (direction) {
 
1605
        case SENDER_IS_INITIATOR:
 
1606
                SIVAL(seq_num, 4, 0x80);
 
1607
                break;
 
1608
        case SENDER_IS_ACCEPTOR:
 
1609
                SIVAL(seq_num, 4, 0x0);
 
1610
                break;
 
1611
        }
 
1612
 
 
1613
        DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
 
1614
        dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
 
1615
 
 
1616
        dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num));
 
1617
 
 
1618
        /* extract the sequence number (key based on supplied packet digest) */
 
1619
        /* needs to be done before the sealing, as the original version 
 
1620
           is used in the sealing stuff... */
 
1621
        schannel_deal_with_seq_num(a, verf);
 
1622
 
 
1623
        if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) {
 
1624
                /* don't even bother with the below if the sequence number is out */
 
1625
                /* The sequence number is MD5'ed with a key based on the whole-packet
 
1626
                   digest, as supplied by the client.  We check that it's a valid 
 
1627
                   checksum after the decode, below
 
1628
                */
 
1629
                DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n"));
 
1630
                dump_data(2, verf->seq_num, sizeof(verf->seq_num));
 
1631
                DEBUG(2, ("should be:\n"));
 
1632
                dump_data(2, seq_num, sizeof(seq_num));
 
1633
 
 
1634
                return False;
 
1635
        }
 
1636
 
 
1637
        if (memcmp(verf->sig, schannel_sig, sizeof(verf->sig))) {
 
1638
                /* Validate that the other end sent the expected header */
 
1639
                DEBUG(2, ("schannel_decode: FAILED: packet header:\n"));
 
1640
                dump_data(2, verf->sig, sizeof(verf->sig));
 
1641
                DEBUG(2, ("should be:\n"));
 
1642
                dump_data(2, schannel_sig, sizeof(schannel_sig));
 
1643
                return False;
 
1644
        }
 
1645
 
 
1646
        if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
 
1647
                uchar sealing_key[16];
 
1648
                
 
1649
                /* get the key to extract the data with */
 
1650
                schannel_get_sealing_key(a, verf, sealing_key);
 
1651
 
 
1652
                /* extract the verification data */
 
1653
                dump_data_pw("verf->confounder:\n", verf->confounder, 
 
1654
                             sizeof(verf->confounder));
 
1655
                SamOEMhash(verf->confounder, sealing_key, 8);
 
1656
 
 
1657
                dump_data_pw("verf->confounder_dec:\n", verf->confounder, 
 
1658
                             sizeof(verf->confounder));
 
1659
                
 
1660
                /* extract the packet payload */
 
1661
                dump_data_pw("data   :\n", (const unsigned char *)data, data_len);
 
1662
                SamOEMhash((unsigned char *)data, sealing_key, data_len);
 
1663
                dump_data_pw("datadec:\n", (const unsigned char *)data, data_len);      
 
1664
        }
 
1665
 
 
1666
        /* digest includes 'data' after unsealing */
 
1667
        schannel_digest(a, auth_level, verf, data, data_len, digest_final);
 
1668
 
 
1669
        dump_data_pw("Calculated digest:\n", digest_final, 
 
1670
                     sizeof(digest_final));
 
1671
        dump_data_pw("verf->packet_digest:\n", verf->packet_digest, 
 
1672
                     sizeof(verf->packet_digest));
 
1673
        
 
1674
        /* compare - if the client got the same result as us, then
 
1675
           it must know the session key */
 
1676
        return (memcmp(digest_final, verf->packet_digest, 
 
1677
                       sizeof(verf->packet_digest)) == 0);
 
1678
}
 
1679
 
 
1680
/*******************************************************************
 
1681
creates a new prs_struct containing a DATA_BLOB
 
1682
********************************************************************/
 
1683
bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 
1684
{
 
1685
        if (!prs_init( prs, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL ))
 
1686
                return False;
 
1687
 
 
1688
 
 
1689
        if (!prs_copy_data_in(prs, (char *)blob->data, blob->length))
 
1690
                return False;
 
1691
 
 
1692
        return True;
 
1693
}
 
1694
 
 
1695
/*******************************************************************
 
1696
return the contents of a prs_struct in a DATA_BLOB
 
1697
********************************************************************/
 
1698
bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 
1699
{
 
1700
        blob->length = prs_data_size(prs);
 
1701
        blob->data = (uint8 *)TALLOC_ZERO_SIZE(mem_ctx, blob->length);
 
1702
        
 
1703
        /* set the pointer at the end of the buffer */
 
1704
        prs_set_offset( prs, prs_data_size(prs) );
 
1705
 
 
1706
        if (!prs_copy_all_data_out((char *)blob->data, prs))
 
1707
                return False;
 
1708
        
 
1709
        return True;
 
1710
}