Line data Source code
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 : #include "reg_parse_prs.h"
25 : #include "rpc_dce.h"
26 :
27 : #undef DBGC_CLASS
28 : #define DBGC_CLASS DBGC_RPC_PARSE
29 :
30 : /*******************************************************************
31 : Debug output for parsing info
32 :
33 : XXXX side-effect of this function is to increase the debug depth XXXX.
34 :
35 : ********************************************************************/
36 :
37 0 : void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name)
38 : {
39 0 : DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(5+depth,depth), ps->data_offset, fn_name, desc));
40 0 : }
41 :
42 : /**
43 : * Initialise an expandable parse structure.
44 : *
45 : * @param size Initial buffer size. If >0, a new buffer will be
46 : * created with talloc().
47 : *
48 : * @return False if allocation fails, otherwise True.
49 : **/
50 :
51 0 : bool prs_init(prs_struct *ps, uint32_t size, TALLOC_CTX *ctx, bool io)
52 : {
53 0 : ZERO_STRUCTP(ps);
54 0 : ps->io = io;
55 0 : ps->bigendian_data = RPC_LITTLE_ENDIAN;
56 0 : ps->align = RPC_PARSE_ALIGN;
57 0 : ps->is_dynamic = False;
58 0 : ps->data_offset = 0;
59 0 : ps->buffer_size = 0;
60 0 : ps->data_p = NULL;
61 0 : ps->mem_ctx = ctx;
62 :
63 0 : if (size != 0) {
64 0 : ps->buffer_size = size;
65 0 : ps->data_p = (char *)talloc_zero_size(ps->mem_ctx, size);
66 0 : if(ps->data_p == NULL) {
67 0 : DEBUG(0,("prs_init: talloc fail for %u bytes.\n", (unsigned int)size));
68 0 : return False;
69 : }
70 0 : ps->is_dynamic = True; /* We own this memory. */
71 0 : } else if (MARSHALLING(ps)) {
72 : /* If size is zero and we're marshalling we should allocate memory on demand. */
73 0 : ps->is_dynamic = True;
74 : }
75 :
76 0 : return True;
77 : }
78 :
79 : /*******************************************************************
80 : Delete the memory in a parse structure - if we own it.
81 :
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 : ********************************************************************/
89 :
90 0 : void prs_mem_free(prs_struct *ps)
91 : {
92 0 : if(ps->is_dynamic) {
93 0 : TALLOC_FREE(ps->data_p);
94 : }
95 0 : ps->is_dynamic = False;
96 0 : ps->buffer_size = 0;
97 0 : ps->data_offset = 0;
98 0 : }
99 :
100 : /*******************************************************************
101 : Allocate memory when unmarshalling... Always zero clears.
102 : ********************************************************************/
103 :
104 : #if defined(PARANOID_MALLOC_CHECKER)
105 0 : char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count)
106 : #else
107 : char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count)
108 : #endif
109 : {
110 0 : char *ret = NULL;
111 :
112 0 : if (size && count) {
113 : /* We can't call the type-safe version here. */
114 0 : ret = (char *)_talloc_zero_array(ps->mem_ctx, size, count,
115 : "parse_prs");
116 : }
117 0 : return ret;
118 : }
119 :
120 : /*******************************************************************
121 : Return the current talloc context we're using.
122 : ********************************************************************/
123 :
124 0 : TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
125 : {
126 0 : return ps->mem_ctx;
127 : }
128 :
129 : /*******************************************************************
130 : Attempt, if needed, to grow a data buffer.
131 : Also depends on the data stream mode (io).
132 : ********************************************************************/
133 :
134 0 : bool prs_grow(prs_struct *ps, uint32_t extra_space)
135 : {
136 : uint32_t new_size;
137 :
138 0 : ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
139 :
140 0 : if(ps->data_offset + extra_space <= ps->buffer_size)
141 0 : return True;
142 :
143 : /*
144 : * We cannot grow the buffer if we're not reading
145 : * into the prs_struct, or if we don't own the memory.
146 : */
147 :
148 0 : if(UNMARSHALLING(ps) || !ps->is_dynamic) {
149 0 : DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
150 : (unsigned int)extra_space));
151 0 : return False;
152 : }
153 :
154 : /*
155 : * Decide how much extra space we really need.
156 : */
157 :
158 0 : extra_space -= (ps->buffer_size - ps->data_offset);
159 0 : if(ps->buffer_size == 0) {
160 :
161 : /*
162 : * Start with 128 bytes (arbitrary value), enough for small rpc
163 : * requests
164 : */
165 0 : new_size = MAX(128, extra_space);
166 :
167 0 : ps->data_p = (char *)talloc_zero_size(ps->mem_ctx, new_size);
168 0 : if(ps->data_p == NULL) {
169 0 : DEBUG(0,("prs_grow: talloc failure for size %u.\n", (unsigned int)new_size));
170 0 : return False;
171 : }
172 : } else {
173 : /*
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.
178 : */
179 0 : new_size = MAX(ps->buffer_size*2,
180 : ps->buffer_size + extra_space + 64);
181 :
182 0 : ps->data_p = talloc_realloc(ps->mem_ctx,
183 : ps->data_p,
184 : char,
185 : new_size);
186 0 : if (ps->data_p == NULL) {
187 0 : DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
188 : (unsigned int)new_size));
189 0 : return False;
190 : }
191 :
192 0 : memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
193 : }
194 0 : ps->buffer_size = new_size;
195 :
196 0 : return True;
197 : }
198 :
199 : /*******************************************************************
200 : Get the data pointer (external interface).
201 : ********************************************************************/
202 :
203 0 : char *prs_data_p(prs_struct *ps)
204 : {
205 0 : return ps->data_p;
206 : }
207 :
208 : /*******************************************************************
209 : Get the current data size (external interface).
210 : ********************************************************************/
211 :
212 0 : uint32_t prs_data_size(prs_struct *ps)
213 : {
214 0 : return ps->buffer_size;
215 : }
216 :
217 : /*******************************************************************
218 : Fetch the current offset (external interface).
219 : ********************************************************************/
220 :
221 0 : uint32_t prs_offset(prs_struct *ps)
222 : {
223 0 : return ps->data_offset;
224 : }
225 :
226 : /*******************************************************************
227 : Set the current offset (external interface).
228 : ********************************************************************/
229 :
230 0 : bool prs_set_offset(prs_struct *ps, uint32_t offset)
231 : {
232 0 : if ((offset > ps->data_offset)
233 0 : && !prs_grow(ps, offset - ps->data_offset)) {
234 0 : return False;
235 : }
236 :
237 0 : ps->data_offset = offset;
238 0 : return True;
239 : }
240 :
241 : /*******************************************************************
242 : Append the data from a buffer into a parse_struct.
243 : ********************************************************************/
244 :
245 0 : bool prs_copy_data_in(prs_struct *dst, const char *src, uint32_t len)
246 : {
247 0 : if (len == 0)
248 0 : return True;
249 :
250 0 : if(!prs_grow(dst, len))
251 0 : return False;
252 :
253 0 : memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
254 0 : dst->data_offset += len;
255 :
256 0 : return True;
257 : }
258 :
259 : /*******************************************************************
260 : Align a the data_len to a multiple of align bytes - filling with
261 : zeros.
262 : ********************************************************************/
263 :
264 0 : bool prs_align(prs_struct *ps)
265 : {
266 0 : uint32_t mod = ps->data_offset & (ps->align-1);
267 :
268 0 : if (ps->align != 0 && mod != 0) {
269 0 : uint32_t extra_space = (ps->align - mod);
270 0 : if(!prs_grow(ps, extra_space))
271 0 : return False;
272 0 : memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
273 0 : ps->data_offset += extra_space;
274 : }
275 :
276 0 : return True;
277 : }
278 :
279 : /******************************************************************
280 : Align on a 8 byte boundary
281 : *****************************************************************/
282 :
283 0 : bool prs_align_uint64(prs_struct *ps)
284 : {
285 : bool ret;
286 0 : uint8_t old_align = ps->align;
287 :
288 0 : ps->align = 8;
289 0 : ret = prs_align(ps);
290 0 : ps->align = old_align;
291 :
292 0 : return ret;
293 : }
294 :
295 : /*******************************************************************
296 : Ensure we can read/write to a given offset.
297 : ********************************************************************/
298 :
299 0 : char *prs_mem_get(prs_struct *ps, uint32_t extra_size)
300 : {
301 0 : if(UNMARSHALLING(ps)) {
302 : /*
303 : * If reading, ensure that we can read the requested size item.
304 : */
305 0 : if (ps->data_offset + extra_size > ps->buffer_size) {
306 0 : 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) ));
310 0 : return NULL;
311 : }
312 : } else {
313 : /*
314 : * Writing - grow the buffer if needed.
315 : */
316 0 : if(!prs_grow(ps, extra_size))
317 0 : return NULL;
318 : }
319 0 : return &ps->data_p[ps->data_offset];
320 : }
321 :
322 : /*******************************************************************
323 : Change the struct type.
324 : ********************************************************************/
325 :
326 0 : void prs_switch_type(prs_struct *ps, bool io)
327 : {
328 0 : if ((ps->io ^ io) == True)
329 0 : ps->io=io;
330 0 : }
331 :
332 : /*******************************************************************
333 : Stream a uint16.
334 : ********************************************************************/
335 :
336 0 : bool prs_uint16(const char *name, prs_struct *ps, int depth, uint16_t *data16)
337 : {
338 0 : char *q = prs_mem_get(ps, sizeof(uint16_t));
339 0 : if (q == NULL)
340 0 : return False;
341 :
342 0 : if (UNMARSHALLING(ps)) {
343 0 : if (ps->bigendian_data)
344 0 : *data16 = RSVAL(q,0);
345 : else
346 0 : *data16 = SVAL(q,0);
347 : } else {
348 0 : if (ps->bigendian_data)
349 0 : RSSVAL(q,0,*data16);
350 : else
351 0 : SSVAL(q,0,*data16);
352 : }
353 :
354 0 : DEBUGADD(5,("%s%04x %s: %04x\n", tab_depth(5,depth), ps->data_offset, name, *data16));
355 :
356 0 : ps->data_offset += sizeof(uint16_t);
357 :
358 0 : return True;
359 : }
360 :
361 : /*******************************************************************
362 : Stream a uint32.
363 : ********************************************************************/
364 :
365 0 : bool prs_uint32(const char *name, prs_struct *ps, int depth, uint32_t *data32)
366 : {
367 0 : char *q = prs_mem_get(ps, sizeof(uint32_t));
368 0 : if (q == NULL)
369 0 : return False;
370 :
371 0 : if (UNMARSHALLING(ps)) {
372 0 : if (ps->bigendian_data)
373 0 : *data32 = RIVAL(q,0);
374 : else
375 0 : *data32 = IVAL(q,0);
376 : } else {
377 0 : if (ps->bigendian_data)
378 0 : RSIVAL(q,0,*data32);
379 : else
380 0 : SIVAL(q,0,*data32);
381 : }
382 :
383 0 : DEBUGADD(5,("%s%04x %s: %08x\n", tab_depth(5,depth), ps->data_offset, name, *data32));
384 :
385 0 : ps->data_offset += sizeof(uint32_t);
386 :
387 0 : return True;
388 : }
389 :
390 : /*******************************************************************
391 : Stream a uint64_struct
392 : ********************************************************************/
393 0 : bool prs_uint64(const char *name, prs_struct *ps, int depth, uint64_t *data64)
394 : {
395 0 : if (UNMARSHALLING(ps)) {
396 : uint32_t high, low;
397 :
398 0 : if (!prs_uint32(name, ps, depth+1, &low))
399 0 : return False;
400 :
401 0 : if (!prs_uint32(name, ps, depth+1, &high))
402 0 : return False;
403 :
404 0 : *data64 = ((uint64_t)high << 32) + low;
405 :
406 0 : return True;
407 : } else {
408 0 : uint32_t high = (*data64) >> 32, low = (*data64) & 0xFFFFFFFF;
409 0 : return prs_uint32(name, ps, depth+1, &low) &&
410 0 : prs_uint32(name, ps, depth+1, &high);
411 : }
412 : }
413 :
414 : /******************************************************************
415 : Stream an array of uint8s. Length is number of uint8s.
416 : ********************************************************************/
417 :
418 0 : bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint8_t *data8s, int len)
419 : {
420 : int i;
421 0 : char *q = prs_mem_get(ps, len);
422 0 : if (q == NULL)
423 0 : return False;
424 :
425 0 : if (UNMARSHALLING(ps)) {
426 0 : for (i = 0; i < len; i++)
427 0 : data8s[i] = CVAL(q,i);
428 : } else {
429 0 : for (i = 0; i < len; i++)
430 0 : SCVAL(q, i, data8s[i]);
431 : }
432 :
433 0 : DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset ,name));
434 0 : if (charmode)
435 0 : print_asc(5, (unsigned char*)data8s, len);
436 : else {
437 0 : for (i = 0; i < len; i++)
438 0 : DEBUGADD(5,("%02x ", data8s[i]));
439 : }
440 0 : DEBUGADD(5,("\n"));
441 :
442 0 : ps->data_offset += len;
443 :
444 0 : return True;
445 : }
|