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 static const char *tab_depth(int level, int depth)
32 if( CHECK_DEBUGLVL(level) ) {
33 dbgtext("%*s", depth*4, "");
38 /*******************************************************************
39 Debug output for parsing info
41 XXXX side-effect of this function is to increase the debug depth XXXX.
43 ********************************************************************/
45 void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name)
47 DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(5+depth,depth), ps->data_offset, fn_name, desc));
51 * Initialise an expandable parse structure.
53 * @param size Initial buffer size. If >0, a new buffer will be
54 * created with talloc().
56 * @return False if allocation fails, otherwise True.
59 bool prs_init(prs_struct *ps, uint32_t size, TALLOC_CTX *ctx, bool io)
63 ps->bigendian_data = RPC_LITTLE_ENDIAN;
64 ps->align = RPC_PARSE_ALIGN;
65 ps->is_dynamic = False;
72 ps->buffer_size = size;
73 ps->data_p = (char *)talloc_zero_size(ps->mem_ctx, size);
74 if(ps->data_p == NULL) {
75 DEBUG(0,("prs_init: talloc fail for %u bytes.\n", (unsigned int)size));
78 ps->is_dynamic = True; /* We own this memory. */
79 } else if (MARSHALLING(ps)) {
80 /* If size is zero and we're marshalling we should allocate memory on demand. */
81 ps->is_dynamic = True;
87 /*******************************************************************
88 Delete the memory in a parse structure - if we own it.
90 NOTE: Contrary to the somewhat confusing naming, this function is not
91 intended for freeing memory allocated by prs_alloc_mem().
92 That memory is also attached to the talloc context given by
93 ps->mem_ctx, but is only freed when that talloc context is
94 freed. prs_mem_free() is used to delete "dynamic" memory
95 allocated in marshalling/unmarshalling.
96 ********************************************************************/
98 void prs_mem_free(prs_struct *ps)
101 TALLOC_FREE(ps->data_p);
103 ps->is_dynamic = False;
108 /*******************************************************************
109 Allocate memory when unmarshalling... Always zero clears.
110 ********************************************************************/
112 #if defined(PARANOID_MALLOC_CHECKER)
113 char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count)
115 char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count)
121 /* We can't call the type-safe version here. */
122 ret = (char *)_talloc_zero_array(ps->mem_ctx, size, count,
128 /*******************************************************************
129 Return the current talloc context we're using.
130 ********************************************************************/
132 TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
137 /*******************************************************************
138 Attempt, if needed, to grow a data buffer.
139 Also depends on the data stream mode (io).
140 ********************************************************************/
142 bool prs_grow(prs_struct *ps, uint32_t extra_space)
146 ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
148 if(ps->data_offset + extra_space <= ps->buffer_size)
152 * We cannot grow the buffer if we're not reading
153 * into the prs_struct, or if we don't own the memory.
156 if(UNMARSHALLING(ps) || !ps->is_dynamic) {
157 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
158 (unsigned int)extra_space));
163 * Decide how much extra space we really need.
166 extra_space -= (ps->buffer_size - ps->data_offset);
167 if(ps->buffer_size == 0) {
170 * Start with 128 bytes (arbitrary value), enough for small rpc
173 new_size = MAX(128, extra_space);
175 ps->data_p = (char *)talloc_zero_size(ps->mem_ctx, new_size);
176 if(ps->data_p == NULL) {
177 DEBUG(0,("prs_grow: talloc failure for size %u.\n", (unsigned int)new_size));
182 * If the current buffer size is bigger than the space needed,
183 * just double it, else add extra_space. Always keep 64 bytes
184 * more, so that after we added a large blob we don't have to
185 * realloc immediately again.
187 new_size = MAX(ps->buffer_size*2,
188 ps->buffer_size + extra_space + 64);
190 ps->data_p = talloc_realloc(ps->mem_ctx,
194 if (ps->data_p == NULL) {
195 DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
196 (unsigned int)new_size));
200 memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
202 ps->buffer_size = new_size;
207 /*******************************************************************
208 Get the data pointer (external interface).
209 ********************************************************************/
211 char *prs_data_p(prs_struct *ps)
216 /*******************************************************************
217 Get the current data size (external interface).
218 ********************************************************************/
220 uint32_t prs_data_size(prs_struct *ps)
222 return ps->buffer_size;
225 /*******************************************************************
226 Fetch the current offset (external interface).
227 ********************************************************************/
229 uint32_t prs_offset(prs_struct *ps)
231 return ps->data_offset;
234 /*******************************************************************
235 Set the current offset (external interface).
236 ********************************************************************/
238 bool prs_set_offset(prs_struct *ps, uint32_t offset)
240 if ((offset > ps->data_offset)
241 && !prs_grow(ps, offset - ps->data_offset)) {
245 ps->data_offset = offset;
249 /*******************************************************************
250 Append the data from a buffer into a parse_struct.
251 ********************************************************************/
253 bool prs_copy_data_in(prs_struct *dst, const char *src, uint32_t len)
258 if(!prs_grow(dst, len))
261 memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
262 dst->data_offset += len;
267 /*******************************************************************
268 Align the data_len to a multiple of align bytes - filling with
270 ********************************************************************/
272 bool prs_align(prs_struct *ps)
274 uint32_t mod = ps->data_offset & (ps->align-1);
276 if (ps->align != 0 && mod != 0) {
277 uint32_t extra_space = (ps->align - mod);
278 if(!prs_grow(ps, extra_space))
280 memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
281 ps->data_offset += extra_space;
287 /******************************************************************
288 Align on a 8 byte boundary
289 *****************************************************************/
291 bool prs_align_uint64(prs_struct *ps)
294 uint8_t old_align = ps->align;
298 ps->align = old_align;
303 /*******************************************************************
304 Ensure we can read/write to a given offset.
305 ********************************************************************/
307 char *prs_mem_get(prs_struct *ps, uint32_t extra_size)
309 if(UNMARSHALLING(ps)) {
311 * If reading, ensure that we can read the requested size item.
313 if (ps->data_offset + extra_size > ps->buffer_size) {
314 DEBUG(0,("prs_mem_get: reading data of size %u would overrun "
315 "buffer by %u bytes.\n",
316 (unsigned int)extra_size,
317 (unsigned int)(ps->data_offset + extra_size - ps->buffer_size) ));
322 * Writing - grow the buffer if needed.
324 if(!prs_grow(ps, extra_size))
327 return &ps->data_p[ps->data_offset];
330 /*******************************************************************
331 Change the struct type.
332 ********************************************************************/
334 void prs_switch_type(prs_struct *ps, bool io)
336 if ((ps->io ^ io) == True)
340 /*******************************************************************
342 ********************************************************************/
344 bool prs_uint16(const char *name, prs_struct *ps, int depth, uint16_t *data16)
346 char *q = prs_mem_get(ps, sizeof(uint16_t));
350 if (UNMARSHALLING(ps)) {
351 if (ps->bigendian_data)
352 *data16 = RSVAL(q,0);
356 if (ps->bigendian_data)
362 DEBUGADD(5,("%s%04x %s: %04x\n", tab_depth(5,depth), ps->data_offset, name, *data16));
364 ps->data_offset += sizeof(uint16_t);
369 /*******************************************************************
371 ********************************************************************/
373 bool prs_uint32(const char *name, prs_struct *ps, int depth, uint32_t *data32)
375 char *q = prs_mem_get(ps, sizeof(uint32_t));
379 if (UNMARSHALLING(ps)) {
380 if (ps->bigendian_data)
381 *data32 = RIVAL(q,0);
385 if (ps->bigendian_data)
391 DEBUGADD(5,("%s%04x %s: %08x\n", tab_depth(5,depth), ps->data_offset, name, *data32));
393 ps->data_offset += sizeof(uint32_t);
398 /*******************************************************************
399 Stream a uint64_struct
400 ********************************************************************/
401 bool prs_uint64(const char *name, prs_struct *ps, int depth, uint64_t *data64)
403 if (UNMARSHALLING(ps)) {
406 if (!prs_uint32(name, ps, depth+1, &low))
409 if (!prs_uint32(name, ps, depth+1, &high))
412 *data64 = ((uint64_t)high << 32) + low;
416 uint32_t high = (*data64) >> 32, low = (*data64) & 0xFFFFFFFF;
417 return prs_uint32(name, ps, depth+1, &low) &&
418 prs_uint32(name, ps, depth+1, &high);
422 /******************************************************************
423 Stream an array of uint8s. Length is number of uint8s.
424 ********************************************************************/
426 bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint8_t *data8s, int len)
429 char *q = prs_mem_get(ps, len);
433 if (UNMARSHALLING(ps)) {
434 for (i = 0; i < len; i++)
435 data8s[i] = CVAL(q,i);
437 for (i = 0; i < len; i++)
438 SCVAL(q, i, data8s[i]);
441 DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset ,name));
443 print_asc(5, (unsigned char*)data8s, len);
445 for (i = 0; i < len; i++)
446 DEBUGADD(5,("%02x ", data8s[i]));
450 ps->data_offset += len;