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