first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[nivanova/samba-autobuild/.git] / source / rpc_parse / parse_prs.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba memory buffer functions
5    Copyright (C) Andrew Tridgell              1992-1997
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1997
7    Copyright (C) Jeremy Allison 1999.
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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 extern int DEBUGLEVEL;
25
26 #include "includes.h"
27
28
29 /*******************************************************************
30  debug output for parsing info.
31
32  XXXX side-effect of this function is to increase the debug depth XXXX
33
34  ********************************************************************/
35 void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name)
36 {
37         DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
38 }
39
40 /*******************************************************************
41  Initialise a parse structure - malloc the data if requested.
42  ********************************************************************/
43
44 BOOL prs_init(prs_struct *ps, uint32 size, uint8 align, BOOL io)
45 {
46         ZERO_STRUCTP(ps);
47         ps->io = io;
48         ps->bigendian_data = False;
49         ps->align = align;
50         ps->is_dynamic = False;
51         ps->data_offset = 0;
52         ps->buffer_size = 0;
53         ps->data_p = NULL;
54
55         if (size != 0) {
56                 ps->buffer_size = size;
57                 if((ps->data_p = (char *)malloc((size_t)size)) == NULL) {
58                         DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
59                         return False;
60                 }
61                 ps->is_dynamic = True; /* We own this memory. */
62         }
63
64         return True;
65 }
66
67 /*******************************************************************
68  Delete the memory in a parse structure - if we own it.
69  ********************************************************************/
70
71 void prs_mem_free(prs_struct *ps)
72 {
73         if(ps->is_dynamic && (ps->data_p != NULL))
74                 free(ps->data_p);
75         ps->is_dynamic = False;
76         ps->data_p = NULL;
77         ps->buffer_size = 0;
78         ps->data_offset = 0;
79 }
80
81 /*******************************************************************
82  Hand some already allocated memory to a prs_struct.
83  ********************************************************************/
84
85 void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic)
86 {
87         ps->is_dynamic = is_dynamic;
88         ps->data_p = buf;
89         ps->buffer_size = size;
90 }
91
92 /*******************************************************************
93  Take some memory back from a prs_struct.
94  ********************************************************************/
95
96 char *prs_take_memory(prs_struct *ps, uint32 *psize)
97 {
98         char *ret = ps->data_p;
99         if(psize)
100                 *psize = ps->buffer_size;
101         ps->is_dynamic = False;
102         prs_mem_free(ps);
103         return ret;
104 }
105
106 /*******************************************************************
107  Attempt, if needed, to grow a data buffer.
108  Also depends on the data stream mode (io).
109  ********************************************************************/
110
111 BOOL prs_grow(prs_struct *ps, uint32 extra_space)
112 {
113         uint32 new_size;
114         char *new_data;
115
116         if(ps->data_offset + extra_space <= ps->buffer_size)
117                 return True;
118
119         /*
120          * We cannot grow the buffer if we're not reading
121          * into the prs_struct, or if we don't own the memory.
122          */
123
124         if(UNMARSHALLING(ps) || !ps->is_dynamic) {
125                 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
126                                 (unsigned int)extra_space));
127                 return False;
128         }
129
130         /*
131          * Decide how much extra space we really need.
132          */
133
134         extra_space -= (ps->buffer_size - ps->data_offset);
135
136         if(ps->buffer_size == 0) {
137
138                 /*
139                  * Ensure we have at least a PDU's length, or extra_space, whichever
140                  * is greater.
141                  */
142
143                 new_size = MAX(MAX_PDU_FRAG_LEN,extra_space);
144
145                 if((new_data = malloc(new_size)) == NULL) {
146                         DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
147                         return False;
148                 }
149                 memset(new_data, '\0', new_size );
150         } else {
151
152                 /*
153                  * If the current buffer size is bigger than the space needed, just 
154                  * double it, else add extra_space.
155                  */
156
157                 new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);
158
159                 if((new_data = Realloc(ps->data_p, new_size)) == NULL) {
160                         DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
161                                 (unsigned int)new_size));
162                         return False;
163                 }
164         }
165
166         ps->buffer_size = new_size;
167         ps->data_p = new_data;
168
169         return True;
170 }
171
172 /*******************************************************************
173  Attempt to force a data buffer to grow by len bytes.
174  This is only used when appending more data onto a prs_struct
175  when reading an rpc reply, before unmarshalling it.
176  ********************************************************************/
177
178 BOOL prs_force_grow(prs_struct *ps, uint32 extra_space)
179 {
180         uint32 new_size = ps->buffer_size + extra_space;
181         char *new_data;
182
183         if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
184                 DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
185                                 (unsigned int)extra_space));
186                 return False;
187         }
188
189         if((new_data = Realloc(ps->data_p, new_size)) == NULL) {
190                 DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
191                         (unsigned int)new_size));
192                 return False;
193         }
194
195         ps->buffer_size = new_size;
196         ps->data_p = new_data;
197
198         return True;
199 }
200
201 /*******************************************************************
202  Get the data pointer (external interface).
203  ********************************************************************/
204
205 char *prs_data_p(prs_struct *ps)
206 {
207         return ps->data_p;
208 }
209
210 /*******************************************************************
211  Get the current data size (external interface).
212  ********************************************************************/
213
214 uint32 prs_data_size(prs_struct *ps)
215 {
216         return ps->buffer_size;
217 }
218
219 /*******************************************************************
220  Fetch the current offset (external interface).
221  ********************************************************************/
222
223 uint32 prs_offset(prs_struct *ps)
224 {
225         return ps->data_offset;
226 }
227
228 /*******************************************************************
229  Set the current offset (external interface).
230  ********************************************************************/
231
232 BOOL prs_set_offset(prs_struct *ps, uint32 offset)
233 {
234         if(offset <= ps->data_offset) {
235                 ps->data_offset = offset;
236                 return True;
237         }
238
239         if(!prs_grow(ps, offset - ps->data_offset))
240                 return False;
241
242         ps->data_offset = offset;
243         return True;
244 }
245
246 /*******************************************************************
247  Append the data from one parse_struct into another.
248  ********************************************************************/
249
250 BOOL prs_append_prs_data(prs_struct *dst, prs_struct *src)
251 {
252         if(!prs_grow(dst, prs_offset(src)))
253                 return False;
254
255         memcpy(&dst->data_p[dst->data_offset], prs_data_p(src), (size_t)prs_offset(src));
256         dst->data_offset += prs_offset(src);
257
258         return True;
259 }
260
261 /*******************************************************************
262  Append the data from a buffer into a parse_struct.
263  ********************************************************************/
264
265 BOOL prs_append_data(prs_struct *dst, char *src, uint32 len)
266 {
267         if(!prs_grow(dst, len))
268                 return False;
269
270         memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
271         dst->data_offset += len;
272
273         return True;
274 }
275
276 /*******************************************************************
277  Set the data as big-endian (external interface).
278  ********************************************************************/
279
280 void prs_set_bigendian_data(prs_struct *ps)
281 {
282         ps->bigendian_data = True;
283 }
284
285 /*******************************************************************
286  Align a the data_len to a multiple of align bytes - filling with
287  zeros.
288  ********************************************************************/
289
290 BOOL prs_align(prs_struct *ps)
291 {
292         uint32 mod = ps->data_offset & (ps->align-1);
293
294         if (ps->align != 0 && mod != 0) {
295                 uint32 extra_space = (ps->align - mod);
296                 if(!prs_grow(ps, extra_space))
297                         return False;
298                 memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
299                 ps->data_offset += extra_space;
300         }
301
302         return True;
303 }
304
305 /*******************************************************************
306  Ensure we can read/write to a given offset.
307  ********************************************************************/
308
309 char *prs_mem_get(prs_struct *ps, uint32 extra_size)
310 {
311         if(UNMARSHALLING(ps)) {
312                 /*
313                  * If reading, ensure that we can read the requested size item.
314                  */
315                 if (ps->data_offset + extra_size > ps->buffer_size) {
316                         DEBUG(0,("prs_mem_get: reading data of size %u would overrun buffer.\n",
317                                         (unsigned int)extra_size ));
318                         return NULL;
319                 }
320         } else {
321                 /*
322                  * Writing - grow the buffer if needed.
323                  */
324                 if(!prs_grow(ps, extra_size))
325                         return False;
326         }
327         return &ps->data_p[ps->data_offset];
328 }
329
330 /*******************************************************************
331  Stream a uint8.
332  ********************************************************************/
333
334 BOOL prs_uint8(char *name, prs_struct *ps, int depth, uint8 *data8)
335 {
336         char *q = prs_mem_get(ps, sizeof(uint8));
337         if (q == NULL)
338                 return False;
339
340         DBG_RW_CVAL(name, depth, ps->data_offset, ps->io, q, *data8)
341         ps->data_offset += sizeof(uint8);
342
343         return True;
344 }
345
346 /*******************************************************************
347  Stream a uint16.
348  ********************************************************************/
349
350 BOOL prs_uint16(char *name, prs_struct *ps, int depth, uint16 *data16)
351 {
352         char *q = prs_mem_get(ps, sizeof(uint16));
353         if (q == NULL)
354                 return False;
355
356         DBG_RW_SVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data16)
357         ps->data_offset += sizeof(uint16);
358
359         return True;
360 }
361
362 /*******************************************************************
363  Stream a uint32.
364  ********************************************************************/
365
366 BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32)
367 {
368         char *q = prs_mem_get(ps, sizeof(uint32));
369         if (q == NULL)
370                 return False;
371
372         DBG_RW_IVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data32)
373         ps->data_offset += sizeof(uint32);
374
375         return True;
376 }
377
378
379 /******************************************************************
380  Stream an array of uint8s. Length is number of uint8s.
381  ********************************************************************/
382
383 BOOL prs_uint8s(BOOL charmode, char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
384 {
385         char *q = prs_mem_get(ps, len * sizeof(uint8));
386         if (q == NULL)
387                 return False;
388
389         DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, data8s, len)
390         ps->data_offset += (len * sizeof(uint8));
391
392         return True;
393 }
394
395 /******************************************************************
396  Stream an array of uint32s. Length is number of uint32s.
397  ********************************************************************/
398
399 BOOL prs_uint32s(BOOL charmode, char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
400 {
401         char *q = prs_mem_get(ps, len * sizeof(uint32));
402         if (q == NULL)
403                 return False;
404
405         DBG_RW_PIVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, data32s, len)
406         ps->data_offset += (len * sizeof(uint32));
407
408         return True;
409 }
410
411 /******************************************************************
412  Stream a "not" unicode string, length/buffer specified separately,
413  in byte chars. String is in little-endian format.
414  ********************************************************************/
415
416 BOOL prs_buffer2(BOOL charmode, char *name, prs_struct *ps, int depth, BUFFER2 *str)
417 {
418         char *p = (char *)str->buffer;
419         char *q = prs_mem_get(ps, str->buf_len);
420         if (q == NULL)
421                 return False;
422
423         /* If we're using big-endian, reverse to get little-endian. */
424         if(ps->bigendian_data)
425                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->buf_len/2)
426         else
427                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->buf_len)
428         ps->data_offset += str->buf_len;
429
430         return True;
431 }
432
433 /******************************************************************
434  Stream a string, length/buffer specified separately,
435  in uint8 chars.
436  ********************************************************************/
437
438 BOOL prs_string2(BOOL charmode, char *name, prs_struct *ps, int depth, STRING2 *str)
439 {
440         char *q = prs_mem_get(ps, str->str_str_len * sizeof(uint8));
441         if (q == NULL)
442                 return False;
443
444         DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, str->buffer, str->str_max_len)
445         ps->data_offset += (str->str_str_len * sizeof(uint8));
446
447         return True;
448 }
449
450 /******************************************************************
451  Stream a unicode string, length/buffer specified separately,
452  in uint16 chars. We use DBG_RW_PCVAL, not DBG_RW_PSVAL here
453  as the unicode string is already in little-endian format.
454  ********************************************************************/
455
456 BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str)
457 {
458         char *p = (char *)str->buffer;
459         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
460         if (q == NULL)
461                 return False;
462
463         /* If we're using big-endian, reverse to get little-endian. */
464         if(ps->bigendian_data)
465                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->uni_str_len)
466         else
467                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->uni_str_len * 2)
468         ps->data_offset += (str->uni_str_len * sizeof(uint16));
469
470         return True;
471 }
472
473 /******************************************************************
474  Stream a unicode string, length/buffer specified separately,
475  in uint16 chars. We use DBG_RW_PCVAL, not DBG_RW_PSVAL here
476  as the unicode string is already in little-endian format.
477  ********************************************************************/
478
479 BOOL prs_unistr3(BOOL charmode, char *name, UNISTR3 *str, prs_struct *ps, int depth)
480 {
481         char *p = (char *)str->str.buffer;
482         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
483         if (q == NULL)
484                 return False;
485
486         /* If we're using big-endian, reverse to get little-endian. */
487         if(ps->bigendian_data)
488                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->uni_str_len)
489         else
490                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->uni_str_len * 2)
491         ps->data_offset += (str->uni_str_len * sizeof(uint16));
492
493         return True;
494 }
495
496 /*******************************************************************
497  Stream a unicode  null-terminated string. As the string is already
498  in little-endian format then do it as a stream of bytes.
499  ********************************************************************/
500
501 BOOL prs_unistr(char *name, prs_struct *ps, int depth, UNISTR *str)
502 {
503         int len = 0;
504         unsigned char *p = (unsigned char *)str->buffer;
505         uint8 *start;
506         char *q;
507
508         for(len = 0; len < (sizeof(str->buffer) / sizeof(str->buffer[0])) &&
509                            str->buffer[len] != 0; len++)
510                 ;
511
512         q = prs_mem_get(ps, len*2);
513         if (q == NULL)
514                 return False;
515
516         start = (uint8*)q;
517
518         len = 0;
519         do 
520         {
521                 if(ps->bigendian_data) {
522                         RW_SVAL(ps->io, ps->bigendian_data, q, *p, 0)
523                         p += 2;
524                         q += 2;
525                 } else {
526                         RW_CVAL(ps->io, q, *p, 0);
527                         p++;
528                         q++;
529                         RW_CVAL(ps->io, q, *p, 0);
530                         p++;
531                         q++;
532                 }
533                 len++;
534         } while ((len < (sizeof(str->buffer) / sizeof(str->buffer[0]))) &&
535                      (str->buffer[len] != 0));
536
537         ps->data_offset += len*2;
538
539         dump_data(5+depth, (char *)start, len * 2);
540
541         return True;
542 }
543
544 /*******************************************************************
545  Stream a null-terminated string.  len is strlen, and therefore does
546  not include the null-termination character.
547  ********************************************************************/
548
549 BOOL prs_string(char *name, prs_struct *ps, int depth, char *str, int len, int max_buf_size)
550 {
551         char *q;
552         uint8 *start;
553         int i;
554
555         len = MIN(len, (max_buf_size-1));
556
557         q = prs_mem_get(ps, len+1);
558         if (q == NULL)
559                 return False;
560
561         start = (uint8*)q;
562
563         for(i = 0; i < len; i++) {
564                 RW_CVAL(ps->io, q, str[i],0);
565                 q++;
566         }
567
568         /* The terminating null. */
569         str[i] = '\0';
570
571         if (MARSHALLING(ps)) {
572                 RW_CVAL(ps->io, q, str[i], 0);
573         }
574
575         ps->data_offset += len+1;
576
577         dump_data(5+depth, (char *)start, len);
578
579         return True;
580 }
581
582 /*******************************************************************
583  prs_uint16 wrapper. Call this and it sets up a pointer to where the
584  uint16 should be stored, or gets the size if reading.
585  ********************************************************************/
586
587 BOOL prs_uint16_pre(char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
588 {
589         (*offset) = ps->data_offset;
590         if (UNMARSHALLING(ps)) {
591                 /* reading. */
592                 return prs_uint16(name, ps, depth, data16);
593         } else {
594                 char *q = prs_mem_get(ps, sizeof(uint16));
595                 if(q ==NULL)
596                         return False;
597                 ps->data_offset += sizeof(uint16);
598         }
599         return True;
600 }
601
602 /*******************************************************************
603  prs_uint16 wrapper.  call this and it retrospectively stores the size.
604  does nothing on reading, as that is already handled by ...._pre()
605  ********************************************************************/
606
607 BOOL prs_uint16_post(char *name, prs_struct *ps, int depth, uint16 *data16,
608                                 uint32 ptr_uint16, uint32 start_offset)
609 {
610         if (MARSHALLING(ps)) {
611                 /* 
612                  * Writing - temporarily move the offset pointer.
613                  */
614                 uint16 data_size = ps->data_offset - start_offset;
615                 uint32 old_offset = ps->data_offset;
616
617                 ps->data_offset = ptr_uint16;
618                 if(!prs_uint16(name, ps, depth, &data_size)) {
619                         ps->data_offset = old_offset;
620                         return False;
621                 }
622                 ps->data_offset = old_offset;
623         } else {
624                 ps->data_offset = start_offset + (uint32)(*data16);
625         }
626         return True;
627 }
628
629 /*******************************************************************
630  prs_uint32 wrapper. Call this and it sets up a pointer to where the
631  uint32 should be stored, or gets the size if reading.
632  ********************************************************************/
633
634 BOOL prs_uint32_pre(char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
635 {
636         (*offset) = ps->data_offset;
637         if (UNMARSHALLING(ps)) {
638                 /* reading. */
639                 return prs_uint32(name, ps, depth, data32);
640         } else {
641                 ps->data_offset += sizeof(uint32);
642         }
643         return True;
644 }
645
646 /*******************************************************************
647  prs_uint32 wrapper.  call this and it retrospectively stores the size.
648  does nothing on reading, as that is already handled by ...._pre()
649  ********************************************************************/
650
651 BOOL prs_uint32_post(char *name, prs_struct *ps, int depth, uint32 *data32,
652                                 uint32 ptr_uint32, uint32 data_size)
653 {
654         if (MARSHALLING(ps)) {
655                 /* 
656                  * Writing - temporarily move the offset pointer.
657                  */
658                 uint32 old_offset = ps->data_offset;
659                 ps->data_offset = ptr_uint32;
660                 if(!prs_uint32(name, ps, depth, &data_size)) {
661                         ps->data_offset = old_offset;
662                         return False;
663                 }
664                 ps->data_offset = old_offset;
665         }
666         return True;
667 }