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
;