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.
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.
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.
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/>.
24 #include "reg_parse_prs.h"
28 #define DBGC_CLASS DBGC_RPC_PARSE
30 /*******************************************************************
31 Debug output for parsing info
33 XXXX side-effect of this function is to increase the debug depth XXXX.
35 ********************************************************************/
37 void prs_debug(prs_struct
*ps
, int depth
, const char *desc
, const char *fn_name
)
39 DEBUG(5+depth
, ("%s%06x %s %s\n", tab_depth(5+depth
,depth
), ps
->data_offset
, fn_name
, desc
));
43 * Initialise an expandable parse structure.
45 * @param size Initial buffer size. If >0, a new buffer will be
46 * created with talloc().
48 * @return False if allocation fails, otherwise True.
51 bool prs_init(prs_struct
*ps
, uint32 size
, TALLOC_CTX
*ctx
, bool io
)
55 ps
->bigendian_data
= RPC_LITTLE_ENDIAN
;
56 ps
->align
= RPC_PARSE_ALIGN
;
57 ps
->is_dynamic
= False
;
64 ps
->buffer_size
= size
;
65 ps
->data_p
= (char *)talloc_zero_size(ps
->mem_ctx
, size
);
66 if(ps
->data_p
== NULL
) {
67 DEBUG(0,("prs_init: talloc fail for %u bytes.\n", (unsigned int)size
));
70 ps
->is_dynamic
= True
; /* We own this memory. */
71 } else if (MARSHALLING(ps
)) {
72 /* If size is zero and we're marshalling we should allocate memory on demand. */
73 ps
->is_dynamic
= True
;
79 /*******************************************************************
80 Delete the memory in a parse structure - if we own it.
82 NOTE: Contrary to the somewhat confusing naming, this function is not
83 intended for freeing memory allocated by prs_alloc_mem().
84 That memory is also attached to the talloc context given by
85 ps->mem_ctx, but is only freed when that talloc context is
86 freed. prs_mem_free() is used to delete "dynamic" memory
87 allocated in marshalling/unmarshalling.
88 ********************************************************************/
90 void prs_mem_free(prs_struct
*ps
)
93 TALLOC_FREE(ps
->data_p
);
95 ps
->is_dynamic
= False
;
100 /*******************************************************************
101 Allocate memory when unmarshalling... Always zero clears.
102 ********************************************************************/
104 #if defined(PARANOID_MALLOC_CHECKER)
105 char *prs_alloc_mem_(prs_struct
*ps
, size_t size
, unsigned int count
)
107 char *prs_alloc_mem(prs_struct
*ps
, size_t size
, unsigned int count
)
113 /* We can't call the type-safe version here. */
114 ret
= (char *)_talloc_zero_array(ps
->mem_ctx
, size
, count
,
120 /*******************************************************************
121 Return the current talloc context we're using.
122 ********************************************************************/
124 TALLOC_CTX
*prs_get_mem_context(prs_struct
*ps
)
129 /*******************************************************************
130 Attempt, if needed, to grow a data buffer.
131 Also depends on the data stream mode (io).
132 ********************************************************************/
134 bool prs_grow(prs_struct
*ps
, uint32 extra_space
)
138 ps
->grow_size
= MAX(ps
->grow_size
, ps
->data_offset
+ extra_space
);
140 if(ps
->data_offset
+ extra_space
<= ps
->buffer_size
)
144 * We cannot grow the buffer if we're not reading
145 * into the prs_struct, or if we don't own the memory.
148 if(UNMARSHALLING(ps
) || !ps
->is_dynamic
) {
149 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
150 (unsigned int)extra_space
));
155 * Decide how much extra space we really need.
158 extra_space
-= (ps
->buffer_size
- ps
->data_offset
);
159 if(ps
->buffer_size
== 0) {
162 * Start with 128 bytes (arbitrary value), enough for small rpc
165 new_size
= MAX(128, extra_space
);
167 ps
->data_p
= (char *)talloc_zero_size(ps
->mem_ctx
, new_size
);
168 if(ps
->data_p
== NULL
) {
169 DEBUG(0,("prs_grow: talloc failure for size %u.\n", (unsigned int)new_size
));
174 * If the current buffer size is bigger than the space needed,
175 * just double it, else add extra_space. Always keep 64 bytes
176 * more, so that after we added a large blob we don't have to
177 * realloc immediately again.
179 new_size
= MAX(ps
->buffer_size
*2,
180 ps
->buffer_size
+ extra_space
+ 64);
182 ps
->data_p
= talloc_realloc(ps
->mem_ctx
,
186 if (ps
->data_p
== NULL
) {
187 DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
188 (unsigned int)new_size
));
192 memset(&ps
->data_p
[ps
->buffer_size
], '\0', (size_t)(new_size
- ps
->buffer_size
));
194 ps
->buffer_size
= new_size
;
199 /*******************************************************************
200 Get the data pointer (external interface).
201 ********************************************************************/
203 char *prs_data_p(prs_struct
*ps
)
208 /*******************************************************************
209 Get the current data size (external interface).
210 ********************************************************************/
212 uint32
prs_data_size(prs_struct
*ps
)
214 return ps
->buffer_size
;
217 /*******************************************************************
218 Fetch the current offset (external interface).
219 ********************************************************************/
221 uint32
prs_offset(prs_struct
*ps
)
223 return ps
->data_offset
;
226 /*******************************************************************
227 Set the current offset (external interface).
228 ********************************************************************/
230 bool prs_set_offset(prs_struct
*ps
, uint32 offset
)
232 if ((offset
> ps
->data_offset
)
233 && !prs_grow(ps
, offset
- ps
->data_offset
)) {
237 ps
->data_offset
= offset
;
241 /*******************************************************************
242 Append the data from a buffer into a parse_struct.
243 ********************************************************************/
245 bool prs_copy_data_in(prs_struct
*dst
, const char *src
, uint32 len
)
250 if(!prs_grow(dst
, len
))
253 memcpy(&dst
->data_p
[dst
->data_offset
], src
, (size_t)len
);
254 dst
->data_offset
+= len
;
259 /*******************************************************************
260 Align a the data_len to a multiple of align bytes - filling with
262 ********************************************************************/
264 bool prs_align(prs_struct
*ps
)
266 uint32 mod
= ps
->data_offset
& (ps
->align
-1);
268 if (ps
->align
!= 0 && mod
!= 0) {
269 uint32 extra_space
= (ps
->align
- mod
);
270 if(!prs_grow(ps
, extra_space
))
272 memset(&ps
->data_p
[ps
->data_offset
], '\0', (size_t)extra_space
);
273 ps
->data_offset
+= extra_space
;
279 /******************************************************************
280 Align on a 8 byte boundary
281 *****************************************************************/
283 bool prs_align_uint64(prs_struct
*ps
)
286 uint8 old_align
= ps
->align
;
290 ps
->align
= old_align
;
295 /*******************************************************************
296 Ensure we can read/write to a given offset.
297 ********************************************************************/
299 char *prs_mem_get(prs_struct
*ps
, uint32 extra_size
)
301 if(UNMARSHALLING(ps
)) {
303 * If reading, ensure that we can read the requested size item.
305 if (ps
->data_offset
+ extra_size
> ps
->buffer_size
) {
306 DEBUG(0,("prs_mem_get: reading data of size %u would overrun "
307 "buffer by %u bytes.\n",
308 (unsigned int)extra_size
,
309 (unsigned int)(ps
->data_offset
+ extra_size
- ps
->buffer_size
) ));
314 * Writing - grow the buffer if needed.
316 if(!prs_grow(ps
, extra_size
))
319 return &ps
->data_p
[ps
->data_offset
];
322 /*******************************************************************
323 Change the struct type.
324 ********************************************************************/
326 void prs_switch_type(prs_struct
*ps
, bool io
)
328 if ((ps
->io
^ io
) == True
)
332 /*******************************************************************
334 ********************************************************************/
336 bool prs_uint16(const char *name
, prs_struct
*ps
, int depth
, uint16
*data16
)
338 char *q
= prs_mem_get(ps
, sizeof(uint16
));
342 if (UNMARSHALLING(ps
)) {
343 if (ps
->bigendian_data
)
344 *data16
= RSVAL(q
,0);
348 if (ps
->bigendian_data
)
354 DEBUGADD(5,("%s%04x %s: %04x\n", tab_depth(5,depth
), ps
->data_offset
, name
, *data16
));
356 ps
->data_offset
+= sizeof(uint16
);
361 /*******************************************************************
363 ********************************************************************/
365 bool prs_uint32(const char *name
, prs_struct
*ps
, int depth
, uint32
*data32
)
367 char *q
= prs_mem_get(ps
, sizeof(uint32
));
371 if (UNMARSHALLING(ps
)) {
372 if (ps
->bigendian_data
)
373 *data32
= RIVAL(q
,0);
377 if (ps
->bigendian_data
)
383 DEBUGADD(5,("%s%04x %s: %08x\n", tab_depth(5,depth
), ps
->data_offset
, name
, *data32
));
385 ps
->data_offset
+= sizeof(uint32
);
390 /*******************************************************************
391 Stream a uint64_struct
392 ********************************************************************/
393 bool prs_uint64(const char *name
, prs_struct
*ps
, int depth
, uint64
*data64
)
395 if (UNMARSHALLING(ps
)) {
398 if (!prs_uint32(name
, ps
, depth
+1, &low
))
401 if (!prs_uint32(name
, ps
, depth
+1, &high
))
404 *data64
= ((uint64_t)high
<< 32) + low
;
408 uint32 high
= (*data64
) >> 32, low
= (*data64
) & 0xFFFFFFFF;
409 return prs_uint32(name
, ps
, depth
+1, &low
) &&
410 prs_uint32(name
, ps
, depth
+1, &high
);
414 /******************************************************************
415 Stream an array of uint8s. Length is number of uint8s.
416 ********************************************************************/
418 bool prs_uint8s(bool charmode
, const char *name
, prs_struct
*ps
, int depth
, uint8
*data8s
, int len
)
421 char *q
= prs_mem_get(ps
, len
);
425 if (UNMARSHALLING(ps
)) {
426 for (i
= 0; i
< len
; i
++)
427 data8s
[i
] = CVAL(q
,i
);
429 for (i
= 0; i
< len
; i
++)
430 SCVAL(q
, i
, data8s
[i
]);
433 DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth
), ps
->data_offset
,name
));
435 print_asc(5, (unsigned char*)data8s
, len
);
437 for (i
= 0; i
< len
; i
++)
438 DEBUGADD(5,("%02x ", data8s
[i
]));
442 ps
->data_offset
+= len
;