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 2 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, write to the Free Software |
---|
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
22 | */ |
---|
23 | |
---|
24 | #include "includes.h" |
---|
25 | |
---|
26 | #undef DBGC_CLASS |
---|
27 | #define DBGC_CLASS DBGC_RPC_PARSE |
---|
28 | |
---|
29 | /** |
---|
30 | * Dump a prs to a file: from the current location through to the end. |
---|
31 | **/ |
---|
32 | void prs_dump(char *name, int v, prs_struct *ps) |
---|
33 | { |
---|
34 | prs_dump_region(name, v, ps, ps->data_offset, ps->buffer_size); |
---|
35 | } |
---|
36 | |
---|
37 | /** |
---|
38 | * Dump from the start of the prs to the current location. |
---|
39 | **/ |
---|
40 | void prs_dump_before(char *name, int v, prs_struct *ps) |
---|
41 | { |
---|
42 | prs_dump_region(name, v, ps, 0, ps->data_offset); |
---|
43 | } |
---|
44 | |
---|
45 | /** |
---|
46 | * Dump everything from the start of the prs up to the current location. |
---|
47 | **/ |
---|
48 | void prs_dump_region(char *name, int v, prs_struct *ps, |
---|
49 | int from_off, int to_off) |
---|
50 | { |
---|
51 | int fd, i; |
---|
52 | pstring fname; |
---|
53 | ssize_t sz; |
---|
54 | if (DEBUGLEVEL < 50) return; |
---|
55 | for (i=1;i<100;i++) { |
---|
56 | if (v != -1) { |
---|
57 | slprintf(fname,sizeof(fname)-1, "/tmp/%s_%d.%d.prs", name, v, i); |
---|
58 | } else { |
---|
59 | slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.prs", name, i); |
---|
60 | } |
---|
61 | fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644); |
---|
62 | if (fd != -1 || errno != EEXIST) break; |
---|
63 | } |
---|
64 | if (fd != -1) { |
---|
65 | sz = write(fd, ps->data_p + from_off, to_off - from_off); |
---|
66 | i = close(fd); |
---|
67 | if ( (sz != to_off-from_off) || (i != 0) ) { |
---|
68 | DEBUG(0,("Error writing/closing %s: %ld!=%ld %d\n", fname, (unsigned long)sz, (unsigned long)to_off-from_off, i )); |
---|
69 | } else { |
---|
70 | DEBUG(0,("created %s\n", fname)); |
---|
71 | } |
---|
72 | } |
---|
73 | } |
---|
74 | |
---|
75 | /******************************************************************* |
---|
76 | Debug output for parsing info |
---|
77 | |
---|
78 | XXXX side-effect of this function is to increase the debug depth XXXX. |
---|
79 | |
---|
80 | ********************************************************************/ |
---|
81 | |
---|
82 | void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name) |
---|
83 | { |
---|
84 | DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc)); |
---|
85 | } |
---|
86 | |
---|
87 | /** |
---|
88 | * Initialise an expandable parse structure. |
---|
89 | * |
---|
90 | * @param size Initial buffer size. If >0, a new buffer will be |
---|
91 | * created with malloc(). |
---|
92 | * |
---|
93 | * @return False if allocation fails, otherwise True. |
---|
94 | **/ |
---|
95 | |
---|
96 | BOOL prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, BOOL io) |
---|
97 | { |
---|
98 | ZERO_STRUCTP(ps); |
---|
99 | ps->io = io; |
---|
100 | ps->bigendian_data = RPC_LITTLE_ENDIAN; |
---|
101 | ps->align = RPC_PARSE_ALIGN; |
---|
102 | ps->is_dynamic = False; |
---|
103 | ps->data_offset = 0; |
---|
104 | ps->buffer_size = 0; |
---|
105 | ps->data_p = NULL; |
---|
106 | ps->mem_ctx = ctx; |
---|
107 | |
---|
108 | if (size != 0) { |
---|
109 | ps->buffer_size = size; |
---|
110 | if((ps->data_p = (char *)SMB_MALLOC((size_t)size)) == NULL) { |
---|
111 | DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size)); |
---|
112 | return False; |
---|
113 | } |
---|
114 | memset(ps->data_p, '\0', (size_t)size); |
---|
115 | ps->is_dynamic = True; /* We own this memory. */ |
---|
116 | } else if (MARSHALLING(ps)) { |
---|
117 | /* If size is zero and we're marshalling we should allocate memory on demand. */ |
---|
118 | ps->is_dynamic = True; |
---|
119 | } |
---|
120 | |
---|
121 | return True; |
---|
122 | } |
---|
123 | |
---|
124 | /******************************************************************* |
---|
125 | Delete the memory in a parse structure - if we own it. |
---|
126 | ********************************************************************/ |
---|
127 | |
---|
128 | void prs_mem_free(prs_struct *ps) |
---|
129 | { |
---|
130 | if(ps->is_dynamic) |
---|
131 | SAFE_FREE(ps->data_p); |
---|
132 | ps->is_dynamic = False; |
---|
133 | ps->buffer_size = 0; |
---|
134 | ps->data_offset = 0; |
---|
135 | } |
---|
136 | |
---|
137 | /******************************************************************* |
---|
138 | Clear the memory in a parse structure. |
---|
139 | ********************************************************************/ |
---|
140 | |
---|
141 | void prs_mem_clear(prs_struct *ps) |
---|
142 | { |
---|
143 | if (ps->buffer_size) |
---|
144 | memset(ps->data_p, '\0', (size_t)ps->buffer_size); |
---|
145 | } |
---|
146 | |
---|
147 | /******************************************************************* |
---|
148 | Allocate memory when unmarshalling... Always zero clears. |
---|
149 | ********************************************************************/ |
---|
150 | |
---|
151 | #if defined(PARANOID_MALLOC_CHECKER) |
---|
152 | char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count) |
---|
153 | #else |
---|
154 | char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count) |
---|
155 | #endif |
---|
156 | { |
---|
157 | char *ret = NULL; |
---|
158 | |
---|
159 | if (size) { |
---|
160 | /* We can't call the type-safe version here. */ |
---|
161 | ret = (char *)_talloc_zero_array(ps->mem_ctx, size, count, |
---|
162 | "parse_prs"); |
---|
163 | } |
---|
164 | return ret; |
---|
165 | } |
---|
166 | |
---|
167 | /******************************************************************* |
---|
168 | Return the current talloc context we're using. |
---|
169 | ********************************************************************/ |
---|
170 | |
---|
171 | TALLOC_CTX *prs_get_mem_context(prs_struct *ps) |
---|
172 | { |
---|
173 | return ps->mem_ctx; |
---|
174 | } |
---|
175 | |
---|
176 | /******************************************************************* |
---|
177 | Hand some already allocated memory to a prs_struct. |
---|
178 | ********************************************************************/ |
---|
179 | |
---|
180 | void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic) |
---|
181 | { |
---|
182 | ps->is_dynamic = is_dynamic; |
---|
183 | ps->data_p = buf; |
---|
184 | ps->buffer_size = size; |
---|
185 | } |
---|
186 | |
---|
187 | /******************************************************************* |
---|
188 | Take some memory back from a prs_struct. |
---|
189 | ********************************************************************/ |
---|
190 | |
---|
191 | char *prs_take_memory(prs_struct *ps, uint32 *psize) |
---|
192 | { |
---|
193 | char *ret = ps->data_p; |
---|
194 | if(psize) |
---|
195 | *psize = ps->buffer_size; |
---|
196 | ps->is_dynamic = False; |
---|
197 | prs_mem_free(ps); |
---|
198 | return ret; |
---|
199 | } |
---|
200 | |
---|
201 | /******************************************************************* |
---|
202 | Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary. |
---|
203 | ********************************************************************/ |
---|
204 | |
---|
205 | BOOL prs_set_buffer_size(prs_struct *ps, uint32 newsize) |
---|
206 | { |
---|
207 | if (newsize > ps->buffer_size) |
---|
208 | return prs_force_grow(ps, newsize - ps->buffer_size); |
---|
209 | |
---|
210 | if (newsize < ps->buffer_size) { |
---|
211 | ps->buffer_size = newsize; |
---|
212 | |
---|
213 | /* newsize == 0 acts as a free and set pointer to NULL */ |
---|
214 | if (newsize == 0) { |
---|
215 | SAFE_FREE(ps->data_p); |
---|
216 | } else { |
---|
217 | ps->data_p = (char *)SMB_REALLOC(ps->data_p, newsize); |
---|
218 | |
---|
219 | if (ps->data_p == NULL) { |
---|
220 | DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n", |
---|
221 | (unsigned int)newsize)); |
---|
222 | DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno))); |
---|
223 | return False; |
---|
224 | } |
---|
225 | } |
---|
226 | } |
---|
227 | |
---|
228 | return True; |
---|
229 | } |
---|
230 | |
---|
231 | /******************************************************************* |
---|
232 | Attempt, if needed, to grow a data buffer. |
---|
233 | Also depends on the data stream mode (io). |
---|
234 | ********************************************************************/ |
---|
235 | |
---|
236 | BOOL prs_grow(prs_struct *ps, uint32 extra_space) |
---|
237 | { |
---|
238 | uint32 new_size; |
---|
239 | |
---|
240 | ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space); |
---|
241 | |
---|
242 | if(ps->data_offset + extra_space <= ps->buffer_size) |
---|
243 | return True; |
---|
244 | |
---|
245 | /* |
---|
246 | * We cannot grow the buffer if we're not reading |
---|
247 | * into the prs_struct, or if we don't own the memory. |
---|
248 | */ |
---|
249 | |
---|
250 | if(UNMARSHALLING(ps) || !ps->is_dynamic) { |
---|
251 | DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n", |
---|
252 | (unsigned int)extra_space)); |
---|
253 | return False; |
---|
254 | } |
---|
255 | |
---|
256 | /* |
---|
257 | * Decide how much extra space we really need. |
---|
258 | */ |
---|
259 | |
---|
260 | extra_space -= (ps->buffer_size - ps->data_offset); |
---|
261 | if(ps->buffer_size == 0) { |
---|
262 | /* |
---|
263 | * Ensure we have at least a PDU's length, or extra_space, whichever |
---|
264 | * is greater. |
---|
265 | */ |
---|
266 | |
---|
267 | new_size = MAX(RPC_MAX_PDU_FRAG_LEN,extra_space); |
---|
268 | |
---|
269 | if((ps->data_p = (char *)SMB_MALLOC(new_size)) == NULL) { |
---|
270 | DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size)); |
---|
271 | return False; |
---|
272 | } |
---|
273 | memset(ps->data_p, '\0', (size_t)new_size ); |
---|
274 | } else { |
---|
275 | /* |
---|
276 | * If the current buffer size is bigger than the space needed, just |
---|
277 | * double it, else add extra_space. |
---|
278 | */ |
---|
279 | new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space); |
---|
280 | |
---|
281 | if ((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) { |
---|
282 | DEBUG(0,("prs_grow: Realloc failure for size %u.\n", |
---|
283 | (unsigned int)new_size)); |
---|
284 | return False; |
---|
285 | } |
---|
286 | |
---|
287 | memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size)); |
---|
288 | } |
---|
289 | ps->buffer_size = new_size; |
---|
290 | |
---|
291 | return True; |
---|
292 | } |
---|
293 | |
---|
294 | /******************************************************************* |
---|
295 | Attempt to force a data buffer to grow by len bytes. |
---|
296 | This is only used when appending more data onto a prs_struct |
---|
297 | when reading an rpc reply, before unmarshalling it. |
---|
298 | ********************************************************************/ |
---|
299 | |
---|
300 | BOOL prs_force_grow(prs_struct *ps, uint32 extra_space) |
---|
301 | { |
---|
302 | uint32 new_size = ps->buffer_size + extra_space; |
---|
303 | |
---|
304 | if(!UNMARSHALLING(ps) || !ps->is_dynamic) { |
---|
305 | DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n", |
---|
306 | (unsigned int)extra_space)); |
---|
307 | return False; |
---|
308 | } |
---|
309 | |
---|
310 | if((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) { |
---|
311 | DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n", |
---|
312 | (unsigned int)new_size)); |
---|
313 | return False; |
---|
314 | } |
---|
315 | |
---|
316 | memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size)); |
---|
317 | |
---|
318 | ps->buffer_size = new_size; |
---|
319 | |
---|
320 | return True; |
---|
321 | } |
---|
322 | |
---|
323 | /******************************************************************* |
---|
324 | Get the data pointer (external interface). |
---|
325 | ********************************************************************/ |
---|
326 | |
---|
327 | char *prs_data_p(prs_struct *ps) |
---|
328 | { |
---|
329 | return ps->data_p; |
---|
330 | } |
---|
331 | |
---|
332 | /******************************************************************* |
---|
333 | Get the current data size (external interface). |
---|
334 | ********************************************************************/ |
---|
335 | |
---|
336 | uint32 prs_data_size(prs_struct *ps) |
---|
337 | { |
---|
338 | return ps->buffer_size; |
---|
339 | } |
---|
340 | |
---|
341 | /******************************************************************* |
---|
342 | Fetch the current offset (external interface). |
---|
343 | ********************************************************************/ |
---|
344 | |
---|
345 | uint32 prs_offset(prs_struct *ps) |
---|
346 | { |
---|
347 | return ps->data_offset; |
---|
348 | } |
---|
349 | |
---|
350 | /******************************************************************* |
---|
351 | Set the current offset (external interface). |
---|
352 | ********************************************************************/ |
---|
353 | |
---|
354 | BOOL prs_set_offset(prs_struct *ps, uint32 offset) |
---|
355 | { |
---|
356 | if(offset <= ps->data_offset) { |
---|
357 | ps->data_offset = offset; |
---|
358 | return True; |
---|
359 | } |
---|
360 | |
---|
361 | if(!prs_grow(ps, offset - ps->data_offset)) |
---|
362 | return False; |
---|
363 | |
---|
364 | ps->data_offset = offset; |
---|
365 | return True; |
---|
366 | } |
---|
367 | |
---|
368 | /******************************************************************* |
---|
369 | Append the data from one parse_struct into another. |
---|
370 | ********************************************************************/ |
---|
371 | |
---|
372 | BOOL prs_append_prs_data(prs_struct *dst, prs_struct *src) |
---|
373 | { |
---|
374 | if (prs_offset(src) == 0) |
---|
375 | return True; |
---|
376 | |
---|
377 | if(!prs_grow(dst, prs_offset(src))) |
---|
378 | return False; |
---|
379 | |
---|
380 | memcpy(&dst->data_p[dst->data_offset], src->data_p, (size_t)prs_offset(src)); |
---|
381 | dst->data_offset += prs_offset(src); |
---|
382 | |
---|
383 | return True; |
---|
384 | } |
---|
385 | |
---|
386 | /******************************************************************* |
---|
387 | Append some data from one parse_struct into another. |
---|
388 | ********************************************************************/ |
---|
389 | |
---|
390 | BOOL prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len) |
---|
391 | { |
---|
392 | if (len == 0) |
---|
393 | return True; |
---|
394 | |
---|
395 | if(!prs_grow(dst, len)) |
---|
396 | return False; |
---|
397 | |
---|
398 | memcpy(&dst->data_p[dst->data_offset], src->data_p + start, (size_t)len); |
---|
399 | dst->data_offset += len; |
---|
400 | |
---|
401 | return True; |
---|
402 | } |
---|
403 | |
---|
404 | /******************************************************************* |
---|
405 | Append the data from a buffer into a parse_struct. |
---|
406 | ********************************************************************/ |
---|
407 | |
---|
408 | BOOL prs_copy_data_in(prs_struct *dst, const char *src, uint32 len) |
---|
409 | { |
---|
410 | if (len == 0) |
---|
411 | return True; |
---|
412 | |
---|
413 | if(!prs_grow(dst, len)) |
---|
414 | return False; |
---|
415 | |
---|
416 | memcpy(&dst->data_p[dst->data_offset], src, (size_t)len); |
---|
417 | dst->data_offset += len; |
---|
418 | |
---|
419 | return True; |
---|
420 | } |
---|
421 | |
---|
422 | /******************************************************************* |
---|
423 | Copy some data from a parse_struct into a buffer. |
---|
424 | ********************************************************************/ |
---|
425 | |
---|
426 | BOOL prs_copy_data_out(char *dst, prs_struct *src, uint32 len) |
---|
427 | { |
---|
428 | if (len == 0) |
---|
429 | return True; |
---|
430 | |
---|
431 | if(!prs_mem_get(src, len)) |
---|
432 | return False; |
---|
433 | |
---|
434 | memcpy(dst, &src->data_p[src->data_offset], (size_t)len); |
---|
435 | src->data_offset += len; |
---|
436 | |
---|
437 | return True; |
---|
438 | } |
---|
439 | |
---|
440 | /******************************************************************* |
---|
441 | Copy all the data from a parse_struct into a buffer. |
---|
442 | ********************************************************************/ |
---|
443 | |
---|
444 | BOOL prs_copy_all_data_out(char *dst, prs_struct *src) |
---|
445 | { |
---|
446 | uint32 len = prs_offset(src); |
---|
447 | |
---|
448 | if (!len) |
---|
449 | return True; |
---|
450 | |
---|
451 | prs_set_offset(src, 0); |
---|
452 | return prs_copy_data_out(dst, src, len); |
---|
453 | } |
---|
454 | |
---|
455 | /******************************************************************* |
---|
456 | Set the data as X-endian (external interface). |
---|
457 | ********************************************************************/ |
---|
458 | |
---|
459 | void prs_set_endian_data(prs_struct *ps, BOOL endian) |
---|
460 | { |
---|
461 | ps->bigendian_data = endian; |
---|
462 | } |
---|
463 | |
---|
464 | /******************************************************************* |
---|
465 | Align a the data_len to a multiple of align bytes - filling with |
---|
466 | zeros. |
---|
467 | ********************************************************************/ |
---|
468 | |
---|
469 | BOOL prs_align(prs_struct *ps) |
---|
470 | { |
---|
471 | uint32 mod = ps->data_offset & (ps->align-1); |
---|
472 | |
---|
473 | if (ps->align != 0 && mod != 0) { |
---|
474 | uint32 extra_space = (ps->align - mod); |
---|
475 | if(!prs_grow(ps, extra_space)) |
---|
476 | return False; |
---|
477 | memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space); |
---|
478 | ps->data_offset += extra_space; |
---|
479 | } |
---|
480 | |
---|
481 | return True; |
---|
482 | } |
---|
483 | |
---|
484 | /****************************************************************** |
---|
485 | Align on a 2 byte boundary |
---|
486 | *****************************************************************/ |
---|
487 | |
---|
488 | BOOL prs_align_uint16(prs_struct *ps) |
---|
489 | { |
---|
490 | BOOL ret; |
---|
491 | uint8 old_align = ps->align; |
---|
492 | |
---|
493 | ps->align = 2; |
---|
494 | ret = prs_align(ps); |
---|
495 | ps->align = old_align; |
---|
496 | |
---|
497 | return ret; |
---|
498 | } |
---|
499 | |
---|
500 | /****************************************************************** |
---|
501 | Align on a 8 byte boundary |
---|
502 | *****************************************************************/ |
---|
503 | |
---|
504 | BOOL prs_align_uint64(prs_struct *ps) |
---|
505 | { |
---|
506 | BOOL ret; |
---|
507 | uint8 old_align = ps->align; |
---|
508 | |
---|
509 | ps->align = 8; |
---|
510 | ret = prs_align(ps); |
---|
511 | ps->align = old_align; |
---|
512 | |
---|
513 | return ret; |
---|
514 | } |
---|
515 | |
---|
516 | /****************************************************************** |
---|
517 | Align on a specific byte boundary |
---|
518 | *****************************************************************/ |
---|
519 | |
---|
520 | BOOL prs_align_custom(prs_struct *ps, uint8 boundary) |
---|
521 | { |
---|
522 | BOOL ret; |
---|
523 | uint8 old_align = ps->align; |
---|
524 | |
---|
525 | ps->align = boundary; |
---|
526 | ret = prs_align(ps); |
---|
527 | ps->align = old_align; |
---|
528 | |
---|
529 | return ret; |
---|
530 | } |
---|
531 | |
---|
532 | |
---|
533 | |
---|
534 | /******************************************************************* |
---|
535 | Align only if required (for the unistr2 string mainly) |
---|
536 | ********************************************************************/ |
---|
537 | |
---|
538 | BOOL prs_align_needed(prs_struct *ps, uint32 needed) |
---|
539 | { |
---|
540 | if (needed==0) |
---|
541 | return True; |
---|
542 | else |
---|
543 | return prs_align(ps); |
---|
544 | } |
---|
545 | |
---|
546 | /******************************************************************* |
---|
547 | Ensure we can read/write to a given offset. |
---|
548 | ********************************************************************/ |
---|
549 | |
---|
550 | char *prs_mem_get(prs_struct *ps, uint32 extra_size) |
---|
551 | { |
---|
552 | if(UNMARSHALLING(ps)) { |
---|
553 | /* |
---|
554 | * If reading, ensure that we can read the requested size item. |
---|
555 | */ |
---|
556 | if (ps->data_offset + extra_size > ps->buffer_size) { |
---|
557 | DEBUG(0,("prs_mem_get: reading data of size %u would overrun " |
---|
558 | "buffer by %u bytes.\n", |
---|
559 | (unsigned int)extra_size, |
---|
560 | (unsigned int)(ps->data_offset + extra_size - ps->buffer_size) )); |
---|
561 | return NULL; |
---|
562 | } |
---|
563 | } else { |
---|
564 | /* |
---|
565 | * Writing - grow the buffer if needed. |
---|
566 | */ |
---|
567 | if(!prs_grow(ps, extra_size)) |
---|
568 | return NULL; |
---|
569 | } |
---|
570 | return &ps->data_p[ps->data_offset]; |
---|
571 | } |
---|
572 | |
---|
573 | /******************************************************************* |
---|
574 | Change the struct type. |
---|
575 | ********************************************************************/ |
---|
576 | |
---|
577 | void prs_switch_type(prs_struct *ps, BOOL io) |
---|
578 | { |
---|
579 | if ((ps->io ^ io) == True) |
---|
580 | ps->io=io; |
---|
581 | } |
---|
582 | |
---|
583 | /******************************************************************* |
---|
584 | Force a prs_struct to be dynamic even when it's size is 0. |
---|
585 | ********************************************************************/ |
---|
586 | |
---|
587 | void prs_force_dynamic(prs_struct *ps) |
---|
588 | { |
---|
589 | ps->is_dynamic=True; |
---|
590 | } |
---|
591 | |
---|
592 | /******************************************************************* |
---|
593 | Associate a session key with a parse struct. |
---|
594 | ********************************************************************/ |
---|
595 | |
---|
596 | void prs_set_session_key(prs_struct *ps, const char sess_key[16]) |
---|
597 | { |
---|
598 | ps->sess_key = sess_key; |
---|
599 | } |
---|
600 | |
---|
601 | /******************************************************************* |
---|
602 | Stream a uint8. |
---|
603 | ********************************************************************/ |
---|
604 | |
---|
605 | BOOL prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8) |
---|
606 | { |
---|
607 | char *q = prs_mem_get(ps, 1); |
---|
608 | if (q == NULL) |
---|
609 | return False; |
---|
610 | |
---|
611 | if (UNMARSHALLING(ps)) |
---|
612 | *data8 = CVAL(q,0); |
---|
613 | else |
---|
614 | SCVAL(q,0,*data8); |
---|
615 | |
---|
616 | DEBUG(5,("%s%04x %s: %02x\n", tab_depth(depth), ps->data_offset, name, *data8)); |
---|
617 | |
---|
618 | ps->data_offset += 1; |
---|
619 | |
---|
620 | return True; |
---|
621 | } |
---|
622 | |
---|
623 | /******************************************************************* |
---|
624 | Stream a uint16* (allocate memory if unmarshalling) |
---|
625 | ********************************************************************/ |
---|
626 | |
---|
627 | BOOL prs_pointer( const char *name, prs_struct *ps, int depth, |
---|
628 | void *dta, size_t data_size, |
---|
629 | BOOL(*prs_fn)(const char*, prs_struct*, int, void*) ) |
---|
630 | { |
---|
631 | void ** data = (void **)dta; |
---|
632 | uint32 data_p; |
---|
633 | |
---|
634 | /* output f000baaa to stream if the pointer is non-zero. */ |
---|
635 | |
---|
636 | data_p = *data ? 0xf000baaa : 0; |
---|
637 | |
---|
638 | if ( !prs_uint32("ptr", ps, depth, &data_p )) |
---|
639 | return False; |
---|
640 | |
---|
641 | /* we're done if there is no data */ |
---|
642 | |
---|
643 | if ( !data_p ) |
---|
644 | return True; |
---|
645 | |
---|
646 | if (UNMARSHALLING(ps)) { |
---|
647 | if ( !(*data = PRS_ALLOC_MEM_VOID(ps, data_size)) ) |
---|
648 | return False; |
---|
649 | } |
---|
650 | |
---|
651 | return prs_fn(name, ps, depth, *data); |
---|
652 | } |
---|
653 | |
---|
654 | |
---|
655 | /******************************************************************* |
---|
656 | Stream a uint16. |
---|
657 | ********************************************************************/ |
---|
658 | |
---|
659 | BOOL prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16) |
---|
660 | { |
---|
661 | char *q = prs_mem_get(ps, sizeof(uint16)); |
---|
662 | if (q == NULL) |
---|
663 | return False; |
---|
664 | |
---|
665 | if (UNMARSHALLING(ps)) { |
---|
666 | if (ps->bigendian_data) |
---|
667 | *data16 = RSVAL(q,0); |
---|
668 | else |
---|
669 | *data16 = SVAL(q,0); |
---|
670 | } else { |
---|
671 | if (ps->bigendian_data) |
---|
672 | RSSVAL(q,0,*data16); |
---|
673 | else |
---|
674 | SSVAL(q,0,*data16); |
---|
675 | } |
---|
676 | |
---|
677 | DEBUG(5,("%s%04x %s: %04x\n", tab_depth(depth), ps->data_offset, name, *data16)); |
---|
678 | |
---|
679 | ps->data_offset += sizeof(uint16); |
---|
680 | |
---|
681 | return True; |
---|
682 | } |
---|
683 | |
---|
684 | /******************************************************************* |
---|
685 | Stream a uint32. |
---|
686 | ********************************************************************/ |
---|
687 | |
---|
688 | BOOL prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32) |
---|
689 | { |
---|
690 | char *q = prs_mem_get(ps, sizeof(uint32)); |
---|
691 | if (q == NULL) |
---|
692 | return False; |
---|
693 | |
---|
694 | if (UNMARSHALLING(ps)) { |
---|
695 | if (ps->bigendian_data) |
---|
696 | *data32 = RIVAL(q,0); |
---|
697 | else |
---|
698 | *data32 = IVAL(q,0); |
---|
699 | } else { |
---|
700 | if (ps->bigendian_data) |
---|
701 | RSIVAL(q,0,*data32); |
---|
702 | else |
---|
703 | SIVAL(q,0,*data32); |
---|
704 | } |
---|
705 | |
---|
706 | DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32)); |
---|
707 | |
---|
708 | ps->data_offset += sizeof(uint32); |
---|
709 | |
---|
710 | return True; |
---|
711 | } |
---|
712 | |
---|
713 | /******************************************************************* |
---|
714 | Stream an int32. |
---|
715 | ********************************************************************/ |
---|
716 | |
---|
717 | BOOL prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32) |
---|
718 | { |
---|
719 | char *q = prs_mem_get(ps, sizeof(int32)); |
---|
720 | if (q == NULL) |
---|
721 | return False; |
---|
722 | |
---|
723 | if (UNMARSHALLING(ps)) { |
---|
724 | if (ps->bigendian_data) |
---|
725 | *data32 = RIVALS(q,0); |
---|
726 | else |
---|
727 | *data32 = IVALS(q,0); |
---|
728 | } else { |
---|
729 | if (ps->bigendian_data) |
---|
730 | RSIVALS(q,0,*data32); |
---|
731 | else |
---|
732 | SIVALS(q,0,*data32); |
---|
733 | } |
---|
734 | |
---|
735 | DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32)); |
---|
736 | |
---|
737 | ps->data_offset += sizeof(int32); |
---|
738 | |
---|
739 | return True; |
---|
740 | } |
---|
741 | |
---|
742 | /******************************************************************* |
---|
743 | Stream a NTSTATUS |
---|
744 | ********************************************************************/ |
---|
745 | |
---|
746 | BOOL prs_ntstatus(const char *name, prs_struct *ps, int depth, NTSTATUS *status) |
---|
747 | { |
---|
748 | char *q = prs_mem_get(ps, sizeof(uint32)); |
---|
749 | if (q == NULL) |
---|
750 | return False; |
---|
751 | |
---|
752 | if (UNMARSHALLING(ps)) { |
---|
753 | if (ps->bigendian_data) |
---|
754 | *status = NT_STATUS(RIVAL(q,0)); |
---|
755 | else |
---|
756 | *status = NT_STATUS(IVAL(q,0)); |
---|
757 | } else { |
---|
758 | if (ps->bigendian_data) |
---|
759 | RSIVAL(q,0,NT_STATUS_V(*status)); |
---|
760 | else |
---|
761 | SIVAL(q,0,NT_STATUS_V(*status)); |
---|
762 | } |
---|
763 | |
---|
764 | DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, |
---|
765 | nt_errstr(*status))); |
---|
766 | |
---|
767 | ps->data_offset += sizeof(uint32); |
---|
768 | |
---|
769 | return True; |
---|
770 | } |
---|
771 | |
---|
772 | /******************************************************************* |
---|
773 | Stream a DCE error code |
---|
774 | ********************************************************************/ |
---|
775 | |
---|
776 | BOOL prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status) |
---|
777 | { |
---|
778 | char *q = prs_mem_get(ps, sizeof(uint32)); |
---|
779 | if (q == NULL) |
---|
780 | return False; |
---|
781 | |
---|
782 | if (UNMARSHALLING(ps)) { |
---|
783 | if (ps->bigendian_data) |
---|
784 | *status = NT_STATUS(RIVAL(q,0)); |
---|
785 | else |
---|
786 | *status = NT_STATUS(IVAL(q,0)); |
---|
787 | } else { |
---|
788 | if (ps->bigendian_data) |
---|
789 | RSIVAL(q,0,NT_STATUS_V(*status)); |
---|
790 | else |
---|
791 | SIVAL(q,0,NT_STATUS_V(*status)); |
---|
792 | } |
---|
793 | |
---|
794 | DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, |
---|
795 | dcerpc_errstr(NT_STATUS_V(*status)))); |
---|
796 | |
---|
797 | ps->data_offset += sizeof(uint32); |
---|
798 | |
---|
799 | return True; |
---|
800 | } |
---|
801 | |
---|
802 | |
---|
803 | /******************************************************************* |
---|
804 | Stream a WERROR |
---|
805 | ********************************************************************/ |
---|
806 | |
---|
807 | BOOL prs_werror(const char *name, prs_struct *ps, int depth, WERROR *status) |
---|
808 | { |
---|
809 | char *q = prs_mem_get(ps, sizeof(uint32)); |
---|
810 | if (q == NULL) |
---|
811 | return False; |
---|
812 | |
---|
813 | if (UNMARSHALLING(ps)) { |
---|
814 | if (ps->bigendian_data) |
---|
815 | *status = W_ERROR(RIVAL(q,0)); |
---|
816 | else |
---|
817 | *status = W_ERROR(IVAL(q,0)); |
---|
818 | } else { |
---|
819 | if (ps->bigendian_data) |
---|
820 | RSIVAL(q,0,W_ERROR_V(*status)); |
---|
821 | else |
---|
822 | SIVAL(q,0,W_ERROR_V(*status)); |
---|
823 | } |
---|
824 | |
---|
825 | DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, |
---|
826 | dos_errstr(*status))); |
---|
827 | |
---|
828 | ps->data_offset += sizeof(uint32); |
---|
829 | |
---|
830 | return True; |
---|
831 | } |
---|
832 | |
---|
833 | |
---|
834 | /****************************************************************** |
---|
835 | Stream an array of uint8s. Length is number of uint8s. |
---|
836 | ********************************************************************/ |
---|
837 | |
---|
838 | BOOL prs_uint8s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len) |
---|
839 | { |
---|
840 | int i; |
---|
841 | char *q = prs_mem_get(ps, len); |
---|
842 | if (q == NULL) |
---|
843 | return False; |
---|
844 | |
---|
845 | if (UNMARSHALLING(ps)) { |
---|
846 | for (i = 0; i < len; i++) |
---|
847 | data8s[i] = CVAL(q,i); |
---|
848 | } else { |
---|
849 | for (i = 0; i < len; i++) |
---|
850 | SCVAL(q, i, data8s[i]); |
---|
851 | } |
---|
852 | |
---|
853 | DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset ,name)); |
---|
854 | if (charmode) |
---|
855 | print_asc(5, (unsigned char*)data8s, len); |
---|
856 | else { |
---|
857 | for (i = 0; i < len; i++) |
---|
858 | DEBUG(5,("%02x ", data8s[i])); |
---|
859 | } |
---|
860 | DEBUG(5,("\n")); |
---|
861 | |
---|
862 | ps->data_offset += len; |
---|
863 | |
---|
864 | return True; |
---|
865 | } |
---|
866 | |
---|
867 | /****************************************************************** |
---|
868 | Stream an array of uint16s. Length is number of uint16s. |
---|
869 | ********************************************************************/ |
---|
870 | |
---|
871 | BOOL prs_uint16s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len) |
---|
872 | { |
---|
873 | int i; |
---|
874 | char *q = prs_mem_get(ps, len * sizeof(uint16)); |
---|
875 | if (q == NULL) |
---|
876 | return False; |
---|
877 | |
---|
878 | if (UNMARSHALLING(ps)) { |
---|
879 | if (ps->bigendian_data) { |
---|
880 | for (i = 0; i < len; i++) |
---|
881 | data16s[i] = RSVAL(q, 2*i); |
---|
882 | } else { |
---|
883 | for (i = 0; i < len; i++) |
---|
884 | data16s[i] = SVAL(q, 2*i); |
---|
885 | } |
---|
886 | } else { |
---|
887 | if (ps->bigendian_data) { |
---|
888 | for (i = 0; i < len; i++) |
---|
889 | RSSVAL(q, 2*i, data16s[i]); |
---|
890 | } else { |
---|
891 | for (i = 0; i < len; i++) |
---|
892 | SSVAL(q, 2*i, data16s[i]); |
---|
893 | } |
---|
894 | } |
---|
895 | |
---|
896 | DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name)); |
---|
897 | if (charmode) |
---|
898 | print_asc(5, (unsigned char*)data16s, 2*len); |
---|
899 | else { |
---|
900 | for (i = 0; i < len; i++) |
---|
901 | DEBUG(5,("%04x ", data16s[i])); |
---|
902 | } |
---|
903 | DEBUG(5,("\n")); |
---|
904 | |
---|
905 | ps->data_offset += (len * sizeof(uint16)); |
---|
906 | |
---|
907 | return True; |
---|
908 | } |
---|
909 | |
---|
910 | /****************************************************************** |
---|
911 | Start using a function for streaming unicode chars. If unmarshalling, |
---|
912 | output must be little-endian, if marshalling, input must be little-endian. |
---|
913 | ********************************************************************/ |
---|
914 | |
---|
915 | static void dbg_rw_punival(BOOL charmode, const char *name, int depth, prs_struct *ps, |
---|
916 | char *in_buf, char *out_buf, int len) |
---|
917 | { |
---|
918 | int i; |
---|
919 | |
---|
920 | if (UNMARSHALLING(ps)) { |
---|
921 | if (ps->bigendian_data) { |
---|
922 | for (i = 0; i < len; i++) |
---|
923 | SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i)); |
---|
924 | } else { |
---|
925 | for (i = 0; i < len; i++) |
---|
926 | SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i)); |
---|
927 | } |
---|
928 | } else { |
---|
929 | if (ps->bigendian_data) { |
---|
930 | for (i = 0; i < len; i++) |
---|
931 | RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i)); |
---|
932 | } else { |
---|
933 | for (i = 0; i < len; i++) |
---|
934 | SSVAL(in_buf, 2*i, SVAL(out_buf,2*i)); |
---|
935 | } |
---|
936 | } |
---|
937 | |
---|
938 | DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name)); |
---|
939 | if (charmode) |
---|
940 | print_asc(5, (unsigned char*)out_buf, 2*len); |
---|
941 | else { |
---|
942 | for (i = 0; i < len; i++) |
---|
943 | DEBUG(5,("%04x ", out_buf[i])); |
---|
944 | } |
---|
945 | DEBUG(5,("\n")); |
---|
946 | } |
---|
947 | |
---|
948 | /****************************************************************** |
---|
949 | Stream a unistr. Always little endian. |
---|
950 | ********************************************************************/ |
---|
951 | |
---|
952 | BOOL prs_uint16uni(BOOL charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len) |
---|
953 | { |
---|
954 | char *q = prs_mem_get(ps, len * sizeof(uint16)); |
---|
955 | if (q == NULL) |
---|
956 | return False; |
---|
957 | |
---|
958 | dbg_rw_punival(charmode, name, depth, ps, q, (char *)data16s, len); |
---|
959 | ps->data_offset += (len * sizeof(uint16)); |
---|
960 | |
---|
961 | return True; |
---|
962 | } |
---|
963 | |
---|
964 | /****************************************************************** |
---|
965 | Stream an array of uint32s. Length is number of uint32s. |
---|
966 | ********************************************************************/ |
---|
967 | |
---|
968 | BOOL prs_uint32s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len) |
---|
969 | { |
---|
970 | int i; |
---|
971 | char *q = prs_mem_get(ps, len * sizeof(uint32)); |
---|
972 | if (q == NULL) |
---|
973 | return False; |
---|
974 | |
---|
975 | if (UNMARSHALLING(ps)) { |
---|
976 | if (ps->bigendian_data) { |
---|
977 | for (i = 0; i < len; i++) |
---|
978 | data32s[i] = RIVAL(q, 4*i); |
---|
979 | } else { |
---|
980 | for (i = 0; i < len; i++) |
---|
981 | data32s[i] = IVAL(q, 4*i); |
---|
982 | } |
---|
983 | } else { |
---|
984 | if (ps->bigendian_data) { |
---|
985 | for (i = 0; i < len; i++) |
---|
986 | RSIVAL(q, 4*i, data32s[i]); |
---|
987 | } else { |
---|
988 | for (i = 0; i < len; i++) |
---|
989 | SIVAL(q, 4*i, data32s[i]); |
---|
990 | } |
---|
991 | } |
---|
992 | |
---|
993 | DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name)); |
---|
994 | if (charmode) |
---|
995 | print_asc(5, (unsigned char*)data32s, 4*len); |
---|
996 | else { |
---|
997 | for (i = 0; i < len; i++) |
---|
998 | DEBUG(5,("%08x ", data32s[i])); |
---|
999 | } |
---|
1000 | DEBUG(5,("\n")); |
---|
1001 | |
---|
1002 | ps->data_offset += (len * sizeof(uint32)); |
---|
1003 | |
---|
1004 | return True; |
---|
1005 | } |
---|
1006 | |
---|
1007 | /****************************************************************** |
---|
1008 | Stream an array of unicode string, length/buffer specified separately, |
---|
1009 | in uint16 chars. The unicode string is already in little-endian format. |
---|
1010 | ********************************************************************/ |
---|
1011 | |
---|
1012 | BOOL prs_buffer5(BOOL charmode, const char *name, prs_struct *ps, int depth, BUFFER5 *str) |
---|
1013 | { |
---|
1014 | char *p; |
---|
1015 | char *q = prs_mem_get(ps, str->buf_len * sizeof(uint16)); |
---|
1016 | if (q == NULL) |
---|
1017 | return False; |
---|
1018 | |
---|
1019 | if (UNMARSHALLING(ps)) { |
---|
1020 | str->buffer = PRS_ALLOC_MEM(ps,uint16,str->buf_len); |
---|
1021 | if (str->buffer == NULL) |
---|
1022 | return False; |
---|
1023 | } |
---|
1024 | |
---|
1025 | /* If the string is empty, we don't have anything to stream */ |
---|
1026 | if (str->buf_len==0) |
---|
1027 | return True; |
---|
1028 | |
---|
1029 | p = (char *)str->buffer; |
---|
1030 | |
---|
1031 | dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len); |
---|
1032 | |
---|
1033 | ps->data_offset += (str->buf_len * sizeof(uint16)); |
---|
1034 | |
---|
1035 | return True; |
---|
1036 | } |
---|
1037 | |
---|
1038 | /****************************************************************** |
---|
1039 | Stream a "not" unicode string, length/buffer specified separately, |
---|
1040 | in byte chars. String is in little-endian format. |
---|
1041 | ********************************************************************/ |
---|
1042 | |
---|
1043 | BOOL prs_regval_buffer(BOOL charmode, const char *name, prs_struct *ps, int depth, REGVAL_BUFFER *buf) |
---|
1044 | { |
---|
1045 | char *p; |
---|
1046 | char *q = prs_mem_get(ps, buf->buf_len); |
---|
1047 | if (q == NULL) |
---|
1048 | return False; |
---|
1049 | |
---|
1050 | if (UNMARSHALLING(ps)) { |
---|
1051 | if (buf->buf_len > buf->buf_max_len) { |
---|
1052 | return False; |
---|
1053 | } |
---|
1054 | if ( buf->buf_max_len ) { |
---|
1055 | buf->buffer = PRS_ALLOC_MEM(ps, uint16, buf->buf_max_len); |
---|
1056 | if ( buf->buffer == NULL ) |
---|
1057 | return False; |
---|
1058 | } |
---|
1059 | } |
---|
1060 | |
---|
1061 | p = (char *)buf->buffer; |
---|
1062 | |
---|
1063 | dbg_rw_punival(charmode, name, depth, ps, q, p, buf->buf_len/2); |
---|
1064 | ps->data_offset += buf->buf_len; |
---|
1065 | |
---|
1066 | return True; |
---|
1067 | } |
---|
1068 | |
---|
1069 | /****************************************************************** |
---|
1070 | Stream a string, length/buffer specified separately, |
---|
1071 | in uint8 chars. |
---|
1072 | ********************************************************************/ |
---|
1073 | |
---|
1074 | BOOL prs_string2(BOOL charmode, const char *name, prs_struct *ps, int depth, STRING2 *str) |
---|
1075 | { |
---|
1076 | unsigned int i; |
---|
1077 | char *q = prs_mem_get(ps, str->str_str_len); |
---|
1078 | if (q == NULL) |
---|
1079 | return False; |
---|
1080 | |
---|
1081 | if (UNMARSHALLING(ps)) { |
---|
1082 | if (str->str_str_len > str->str_max_len) { |
---|
1083 | return False; |
---|
1084 | } |
---|
1085 | str->buffer = PRS_ALLOC_MEM(ps,unsigned char, str->str_max_len); |
---|
1086 | if (str->buffer == NULL) |
---|
1087 | return False; |
---|
1088 | } |
---|
1089 | |
---|
1090 | if (UNMARSHALLING(ps)) { |
---|
1091 | for (i = 0; i < str->str_str_len; i++) |
---|
1092 | str->buffer[i] = CVAL(q,i); |
---|
1093 | } else { |
---|
1094 | for (i = 0; i < str->str_str_len; i++) |
---|
1095 | SCVAL(q, i, str->buffer[i]); |
---|
1096 | } |
---|
1097 | |
---|
1098 | DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name)); |
---|
1099 | if (charmode) |
---|
1100 | print_asc(5, (unsigned char*)str->buffer, str->str_str_len); |
---|
1101 | else { |
---|
1102 | for (i = 0; i < str->str_str_len; i++) |
---|
1103 | DEBUG(5,("%02x ", str->buffer[i])); |
---|
1104 | } |
---|
1105 | DEBUG(5,("\n")); |
---|
1106 | |
---|
1107 | ps->data_offset += str->str_str_len; |
---|
1108 | |
---|
1109 | return True; |
---|
1110 | } |
---|
1111 | |
---|
1112 | /****************************************************************** |
---|
1113 | Stream a unicode string, length/buffer specified separately, |
---|
1114 | in uint16 chars. The unicode string is already in little-endian format. |
---|
1115 | ********************************************************************/ |
---|
1116 | |
---|
1117 | BOOL prs_unistr2(BOOL charmode, const char *name, prs_struct *ps, int depth, UNISTR2 *str) |
---|
1118 | { |
---|
1119 | char *p; |
---|
1120 | char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16)); |
---|
1121 | if (q == NULL) |
---|
1122 | return False; |
---|
1123 | |
---|
1124 | /* If the string is empty, we don't have anything to stream */ |
---|
1125 | if (str->uni_str_len==0) |
---|
1126 | return True; |
---|
1127 | |
---|
1128 | if (UNMARSHALLING(ps)) { |
---|
1129 | if (str->uni_str_len > str->uni_max_len) { |
---|
1130 | return False; |
---|
1131 | } |
---|
1132 | str->buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_max_len); |
---|
1133 | if (str->buffer == NULL) |
---|
1134 | return False; |
---|
1135 | } |
---|
1136 | |
---|
1137 | p = (char *)str->buffer; |
---|
1138 | |
---|
1139 | dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len); |
---|
1140 | |
---|
1141 | ps->data_offset += (str->uni_str_len * sizeof(uint16)); |
---|
1142 | |
---|
1143 | return True; |
---|
1144 | } |
---|
1145 | |
---|
1146 | /****************************************************************** |
---|
1147 | Stream a unicode string, length/buffer specified separately, |
---|
1148 | in uint16 chars. The unicode string is already in little-endian format. |
---|
1149 | ********************************************************************/ |
---|
1150 | |
---|
1151 | BOOL prs_unistr3(BOOL charmode, const char *name, UNISTR3 *str, prs_struct *ps, int depth) |
---|
1152 | { |
---|
1153 | char *p; |
---|
1154 | char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16)); |
---|
1155 | if (q == NULL) |
---|
1156 | return False; |
---|
1157 | |
---|
1158 | if (UNMARSHALLING(ps)) { |
---|
1159 | str->str.buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_str_len); |
---|
1160 | if (str->str.buffer == NULL) |
---|
1161 | return False; |
---|
1162 | } |
---|
1163 | |
---|
1164 | p = (char *)str->str.buffer; |
---|
1165 | |
---|
1166 | dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len); |
---|
1167 | ps->data_offset += (str->uni_str_len * sizeof(uint16)); |
---|
1168 | |
---|
1169 | return True; |
---|
1170 | } |
---|
1171 | |
---|
1172 | /******************************************************************* |
---|
1173 | Stream a unicode null-terminated string. As the string is already |
---|
1174 | in little-endian format then do it as a stream of bytes. |
---|
1175 | ********************************************************************/ |
---|
1176 | |
---|
1177 | BOOL prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str) |
---|
1178 | { |
---|
1179 | unsigned int len = 0; |
---|
1180 | unsigned char *p = (unsigned char *)str->buffer; |
---|
1181 | uint8 *start; |
---|
1182 | char *q; |
---|
1183 | uint32 max_len; |
---|
1184 | uint16* ptr; |
---|
1185 | |
---|
1186 | if (MARSHALLING(ps)) { |
---|
1187 | |
---|
1188 | for(len = 0; str->buffer[len] != 0; len++) |
---|
1189 | ; |
---|
1190 | |
---|
1191 | q = prs_mem_get(ps, (len+1)*2); |
---|
1192 | if (q == NULL) |
---|
1193 | return False; |
---|
1194 | |
---|
1195 | start = (uint8*)q; |
---|
1196 | |
---|
1197 | for(len = 0; str->buffer[len] != 0; len++) { |
---|
1198 | if(ps->bigendian_data) { |
---|
1199 | /* swap bytes - p is little endian, q is big endian. */ |
---|
1200 | q[0] = (char)p[1]; |
---|
1201 | q[1] = (char)p[0]; |
---|
1202 | p += 2; |
---|
1203 | q += 2; |
---|
1204 | } |
---|
1205 | else |
---|
1206 | { |
---|
1207 | q[0] = (char)p[0]; |
---|
1208 | q[1] = (char)p[1]; |
---|
1209 | p += 2; |
---|
1210 | q += 2; |
---|
1211 | } |
---|
1212 | } |
---|
1213 | |
---|
1214 | /* |
---|
1215 | * even if the string is 'empty' (only an \0 char) |
---|
1216 | * at this point the leading \0 hasn't been parsed. |
---|
1217 | * so parse it now |
---|
1218 | */ |
---|
1219 | |
---|
1220 | q[0] = 0; |
---|
1221 | q[1] = 0; |
---|
1222 | q += 2; |
---|
1223 | |
---|
1224 | len++; |
---|
1225 | |
---|
1226 | DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name)); |
---|
1227 | print_asc(5, (unsigned char*)start, 2*len); |
---|
1228 | DEBUG(5, ("\n")); |
---|
1229 | } |
---|
1230 | else { /* unmarshalling */ |
---|
1231 | |
---|
1232 | uint32 alloc_len = 0; |
---|
1233 | q = ps->data_p + prs_offset(ps); |
---|
1234 | |
---|
1235 | /* |
---|
1236 | * Work out how much space we need and talloc it. |
---|
1237 | */ |
---|
1238 | max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16); |
---|
1239 | |
---|
1240 | /* the test of the value of *ptr helps to catch the circumstance |
---|
1241 | where we have an emtpty (non-existent) string in the buffer */ |
---|
1242 | for ( ptr = (uint16 *)q; *ptr++ && (alloc_len <= max_len); alloc_len++) |
---|
1243 | /* do nothing */ |
---|
1244 | ; |
---|
1245 | |
---|
1246 | if (alloc_len < max_len) |
---|
1247 | alloc_len += 1; |
---|
1248 | |
---|
1249 | /* should we allocate anything at all? */ |
---|
1250 | str->buffer = PRS_ALLOC_MEM(ps,uint16,alloc_len); |
---|
1251 | if ((str->buffer == NULL) && (alloc_len > 0)) |
---|
1252 | return False; |
---|
1253 | |
---|
1254 | p = (unsigned char *)str->buffer; |
---|
1255 | |
---|
1256 | len = 0; |
---|
1257 | /* the (len < alloc_len) test is to prevent us from overwriting |
---|
1258 | memory that is not ours...if we get that far, we have a non-null |
---|
1259 | terminated string in the buffer and have messed up somewhere */ |
---|
1260 | while ((len < alloc_len) && (*(uint16 *)q != 0)) { |
---|
1261 | if(ps->bigendian_data) |
---|
1262 | { |
---|
1263 | /* swap bytes - q is big endian, p is little endian. */ |
---|
1264 | p[0] = (unsigned char)q[1]; |
---|
1265 | p[1] = (unsigned char)q[0]; |
---|
1266 | p += 2; |
---|
1267 | q += 2; |
---|
1268 | } else { |
---|
1269 | |
---|
1270 | p[0] = (unsigned char)q[0]; |
---|
1271 | p[1] = (unsigned char)q[1]; |
---|
1272 | p += 2; |
---|
1273 | q += 2; |
---|
1274 | } |
---|
1275 | |
---|
1276 | len++; |
---|
1277 | } |
---|
1278 | if (len < alloc_len) { |
---|
1279 | /* NULL terminate the UNISTR */ |
---|
1280 | str->buffer[len++] = '\0'; |
---|
1281 | } |
---|
1282 | |
---|
1283 | DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name)); |
---|
1284 | print_asc(5, (unsigned char*)str->buffer, 2*len); |
---|
1285 | DEBUG(5, ("\n")); |
---|
1286 | } |
---|
1287 | |
---|
1288 | /* set the offset in the prs_struct; 'len' points to the |
---|
1289 | terminiating NULL in the UNISTR so we need to go one more |
---|
1290 | uint16 */ |
---|
1291 | ps->data_offset += (len)*2; |
---|
1292 | |
---|
1293 | return True; |
---|
1294 | } |
---|
1295 | |
---|
1296 | |
---|
1297 | /******************************************************************* |
---|
1298 | Stream a null-terminated string. len is strlen, and therefore does |
---|
1299 | not include the null-termination character. |
---|
1300 | ********************************************************************/ |
---|
1301 | |
---|
1302 | BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size) |
---|
1303 | { |
---|
1304 | char *q; |
---|
1305 | int i; |
---|
1306 | int len; |
---|
1307 | |
---|
1308 | if (UNMARSHALLING(ps)) |
---|
1309 | len = strlen(&ps->data_p[ps->data_offset]); |
---|
1310 | else |
---|
1311 | len = strlen(str); |
---|
1312 | |
---|
1313 | len = MIN(len, (max_buf_size-1)); |
---|
1314 | |
---|
1315 | q = prs_mem_get(ps, len+1); |
---|
1316 | if (q == NULL) |
---|
1317 | return False; |
---|
1318 | |
---|
1319 | for(i = 0; i < len; i++) { |
---|
1320 | if (UNMARSHALLING(ps)) |
---|
1321 | str[i] = q[i]; |
---|
1322 | else |
---|
1323 | q[i] = str[i]; |
---|
1324 | } |
---|
1325 | |
---|
1326 | /* The terminating null. */ |
---|
1327 | str[i] = '\0'; |
---|
1328 | |
---|
1329 | if (MARSHALLING(ps)) { |
---|
1330 | q[i] = '\0'; |
---|
1331 | } |
---|
1332 | |
---|
1333 | ps->data_offset += len+1; |
---|
1334 | |
---|
1335 | dump_data(5+depth, q, len); |
---|
1336 | |
---|
1337 | return True; |
---|
1338 | } |
---|
1339 | |
---|
1340 | BOOL prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str) |
---|
1341 | { |
---|
1342 | size_t len; |
---|
1343 | char *tmp_str; |
---|
1344 | |
---|
1345 | if (UNMARSHALLING(ps)) { |
---|
1346 | len = strlen(&ps->data_p[ps->data_offset]); |
---|
1347 | } else { |
---|
1348 | len = strlen(*str); |
---|
1349 | } |
---|
1350 | |
---|
1351 | tmp_str = PRS_ALLOC_MEM(ps, char, len+1); |
---|
1352 | |
---|
1353 | if (tmp_str == NULL) { |
---|
1354 | return False; |
---|
1355 | } |
---|
1356 | |
---|
1357 | if (MARSHALLING(ps)) { |
---|
1358 | strncpy(tmp_str, *str, len); |
---|
1359 | } |
---|
1360 | |
---|
1361 | if (!prs_string(name, ps, depth, tmp_str, len+1)) { |
---|
1362 | return False; |
---|
1363 | } |
---|
1364 | |
---|
1365 | *str = tmp_str; |
---|
1366 | return True; |
---|
1367 | } |
---|
1368 | |
---|
1369 | /******************************************************************* |
---|
1370 | prs_uint16 wrapper. Call this and it sets up a pointer to where the |
---|
1371 | uint16 should be stored, or gets the size if reading. |
---|
1372 | ********************************************************************/ |
---|
1373 | |
---|
1374 | BOOL prs_uint16_pre(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset) |
---|
1375 | { |
---|
1376 | *offset = ps->data_offset; |
---|
1377 | if (UNMARSHALLING(ps)) { |
---|
1378 | /* reading. */ |
---|
1379 | return prs_uint16(name, ps, depth, data16); |
---|
1380 | } else { |
---|
1381 | char *q = prs_mem_get(ps, sizeof(uint16)); |
---|
1382 | if(q ==NULL) |
---|
1383 | return False; |
---|
1384 | ps->data_offset += sizeof(uint16); |
---|
1385 | } |
---|
1386 | return True; |
---|
1387 | } |
---|
1388 | |
---|
1389 | /******************************************************************* |
---|
1390 | prs_uint16 wrapper. call this and it retrospectively stores the size. |
---|
1391 | does nothing on reading, as that is already handled by ...._pre() |
---|
1392 | ********************************************************************/ |
---|
1393 | |
---|
1394 | BOOL prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16, |
---|
1395 | uint32 ptr_uint16, uint32 start_offset) |
---|
1396 | { |
---|
1397 | if (MARSHALLING(ps)) { |
---|
1398 | /* |
---|
1399 | * Writing - temporarily move the offset pointer. |
---|
1400 | */ |
---|
1401 | uint16 data_size = ps->data_offset - start_offset; |
---|
1402 | uint32 old_offset = ps->data_offset; |
---|
1403 | |
---|
1404 | ps->data_offset = ptr_uint16; |
---|
1405 | if(!prs_uint16(name, ps, depth, &data_size)) { |
---|
1406 | ps->data_offset = old_offset; |
---|
1407 | return False; |
---|
1408 | } |
---|
1409 | ps->data_offset = old_offset; |
---|
1410 | } else { |
---|
1411 | ps->data_offset = start_offset + (uint32)(*data16); |
---|
1412 | } |
---|
1413 | return True; |
---|
1414 | } |
---|
1415 | |
---|
1416 | /******************************************************************* |
---|
1417 | prs_uint32 wrapper. Call this and it sets up a pointer to where the |
---|
1418 | uint32 should be stored, or gets the size if reading. |
---|
1419 | ********************************************************************/ |
---|
1420 | |
---|
1421 | BOOL prs_uint32_pre(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset) |
---|
1422 | { |
---|
1423 | *offset = ps->data_offset; |
---|
1424 | if (UNMARSHALLING(ps) && (data32 != NULL)) { |
---|
1425 | /* reading. */ |
---|
1426 | return prs_uint32(name, ps, depth, data32); |
---|
1427 | } else { |
---|
1428 | ps->data_offset += sizeof(uint32); |
---|
1429 | } |
---|
1430 | return True; |
---|
1431 | } |
---|
1432 | |
---|
1433 | /******************************************************************* |
---|
1434 | prs_uint32 wrapper. call this and it retrospectively stores the size. |
---|
1435 | does nothing on reading, as that is already handled by ...._pre() |
---|
1436 | ********************************************************************/ |
---|
1437 | |
---|
1438 | BOOL prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32, |
---|
1439 | uint32 ptr_uint32, uint32 data_size) |
---|
1440 | { |
---|
1441 | if (MARSHALLING(ps)) { |
---|
1442 | /* |
---|
1443 | * Writing - temporarily move the offset pointer. |
---|
1444 | */ |
---|
1445 | uint32 old_offset = ps->data_offset; |
---|
1446 | ps->data_offset = ptr_uint32; |
---|
1447 | if(!prs_uint32(name, ps, depth, &data_size)) { |
---|
1448 | ps->data_offset = old_offset; |
---|
1449 | return False; |
---|
1450 | } |
---|
1451 | ps->data_offset = old_offset; |
---|
1452 | } |
---|
1453 | return True; |
---|
1454 | } |
---|
1455 | |
---|
1456 | /* useful function to store a structure in rpc wire format */ |
---|
1457 | int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps) |
---|
1458 | { |
---|
1459 | TDB_DATA kbuf, dbuf; |
---|
1460 | kbuf.dptr = keystr; |
---|
1461 | kbuf.dsize = strlen(keystr)+1; |
---|
1462 | dbuf.dptr = ps->data_p; |
---|
1463 | dbuf.dsize = prs_offset(ps); |
---|
1464 | return tdb_trans_store(tdb, kbuf, dbuf, TDB_REPLACE); |
---|
1465 | } |
---|
1466 | |
---|
1467 | /* useful function to fetch a structure into rpc wire format */ |
---|
1468 | int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps, TALLOC_CTX *mem_ctx) |
---|
1469 | { |
---|
1470 | TDB_DATA kbuf, dbuf; |
---|
1471 | kbuf.dptr = keystr; |
---|
1472 | kbuf.dsize = strlen(keystr)+1; |
---|
1473 | |
---|
1474 | prs_init(ps, 0, mem_ctx, UNMARSHALL); |
---|
1475 | |
---|
1476 | dbuf = tdb_fetch(tdb, kbuf); |
---|
1477 | if (!dbuf.dptr) |
---|
1478 | return -1; |
---|
1479 | |
---|
1480 | prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True); |
---|
1481 | |
---|
1482 | return 0; |
---|
1483 | } |
---|
1484 | |
---|
1485 | /******************************************************************* |
---|
1486 | hash a stream. |
---|
1487 | ********************************************************************/ |
---|
1488 | |
---|
1489 | BOOL prs_hash1(prs_struct *ps, uint32 offset, int len) |
---|
1490 | { |
---|
1491 | char *q; |
---|
1492 | |
---|
1493 | q = ps->data_p; |
---|
1494 | q = &q[offset]; |
---|
1495 | |
---|
1496 | #ifdef DEBUG_PASSWORD |
---|
1497 | DEBUG(100, ("prs_hash1\n")); |
---|
1498 | dump_data(100, ps->sess_key, 16); |
---|
1499 | dump_data(100, q, len); |
---|
1500 | #endif |
---|
1501 | SamOEMhash((uchar *) q, (const unsigned char *)ps->sess_key, len); |
---|
1502 | |
---|
1503 | #ifdef DEBUG_PASSWORD |
---|
1504 | dump_data(100, q, len); |
---|
1505 | #endif |
---|
1506 | |
---|
1507 | return True; |
---|
1508 | } |
---|
1509 | |
---|
1510 | /******************************************************************* |
---|
1511 | Create a digest over the entire packet (including the data), and |
---|
1512 | MD5 it with the session key. |
---|
1513 | ********************************************************************/ |
---|
1514 | |
---|
1515 | static void schannel_digest(struct schannel_auth_struct *a, |
---|
1516 | enum pipe_auth_level auth_level, |
---|
1517 | RPC_AUTH_SCHANNEL_CHK * verf, |
---|
1518 | char *data, size_t data_len, |
---|
1519 | uchar digest_final[16]) |
---|
1520 | { |
---|
1521 | uchar whole_packet_digest[16]; |
---|
1522 | static uchar zeros[4]; |
---|
1523 | struct MD5Context ctx3; |
---|
1524 | |
---|
1525 | /* verfiy the signature on the packet by MD5 over various bits */ |
---|
1526 | MD5Init(&ctx3); |
---|
1527 | /* use our sequence number, which ensures the packet is not |
---|
1528 | out of order */ |
---|
1529 | MD5Update(&ctx3, zeros, sizeof(zeros)); |
---|
1530 | MD5Update(&ctx3, verf->sig, sizeof(verf->sig)); |
---|
1531 | if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { |
---|
1532 | MD5Update(&ctx3, verf->confounder, sizeof(verf->confounder)); |
---|
1533 | } |
---|
1534 | MD5Update(&ctx3, (const unsigned char *)data, data_len); |
---|
1535 | MD5Final(whole_packet_digest, &ctx3); |
---|
1536 | dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest)); |
---|
1537 | |
---|
1538 | /* MD5 this result and the session key, to prove that |
---|
1539 | only a valid client could had produced this */ |
---|
1540 | hmac_md5(a->sess_key, whole_packet_digest, sizeof(whole_packet_digest), digest_final); |
---|
1541 | } |
---|
1542 | |
---|
1543 | /******************************************************************* |
---|
1544 | Calculate the key with which to encode the data payload |
---|
1545 | ********************************************************************/ |
---|
1546 | |
---|
1547 | static void schannel_get_sealing_key(struct schannel_auth_struct *a, |
---|
1548 | RPC_AUTH_SCHANNEL_CHK *verf, |
---|
1549 | uchar sealing_key[16]) |
---|
1550 | { |
---|
1551 | static uchar zeros[4]; |
---|
1552 | uchar digest2[16]; |
---|
1553 | uchar sess_kf0[16]; |
---|
1554 | int i; |
---|
1555 | |
---|
1556 | for (i = 0; i < sizeof(sess_kf0); i++) { |
---|
1557 | sess_kf0[i] = a->sess_key[i] ^ 0xf0; |
---|
1558 | } |
---|
1559 | |
---|
1560 | dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0)); |
---|
1561 | |
---|
1562 | /* MD5 of sess_kf0 and 4 zero bytes */ |
---|
1563 | hmac_md5(sess_kf0, zeros, 0x4, digest2); |
---|
1564 | dump_data_pw("digest2:\n", digest2, sizeof(digest2)); |
---|
1565 | |
---|
1566 | /* MD5 of the above result, plus 8 bytes of sequence number */ |
---|
1567 | hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key); |
---|
1568 | dump_data_pw("sealing_key:\n", sealing_key, 16); |
---|
1569 | } |
---|
1570 | |
---|
1571 | /******************************************************************* |
---|
1572 | Encode or Decode the sequence number (which is symmetric) |
---|
1573 | ********************************************************************/ |
---|
1574 | |
---|
1575 | static void schannel_deal_with_seq_num(struct schannel_auth_struct *a, |
---|
1576 | RPC_AUTH_SCHANNEL_CHK *verf) |
---|
1577 | { |
---|
1578 | static uchar zeros[4]; |
---|
1579 | uchar sequence_key[16]; |
---|
1580 | uchar digest1[16]; |
---|
1581 | |
---|
1582 | hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1); |
---|
1583 | dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1)); |
---|
1584 | |
---|
1585 | hmac_md5(digest1, verf->packet_digest, 8, sequence_key); |
---|
1586 | |
---|
1587 | dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key)); |
---|
1588 | |
---|
1589 | dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num)); |
---|
1590 | SamOEMhash(verf->seq_num, sequence_key, 8); |
---|
1591 | dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num)); |
---|
1592 | } |
---|
1593 | |
---|
1594 | /******************************************************************* |
---|
1595 | creates an RPC_AUTH_SCHANNEL_CHK structure. |
---|
1596 | ********************************************************************/ |
---|
1597 | |
---|
1598 | static BOOL init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk, |
---|
1599 | const uchar sig[8], |
---|
1600 | const uchar packet_digest[8], |
---|
1601 | const uchar seq_num[8], const uchar confounder[8]) |
---|
1602 | { |
---|
1603 | if (chk == NULL) |
---|
1604 | return False; |
---|
1605 | |
---|
1606 | memcpy(chk->sig, sig, sizeof(chk->sig)); |
---|
1607 | memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest)); |
---|
1608 | memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num)); |
---|
1609 | memcpy(chk->confounder, confounder, sizeof(chk->confounder)); |
---|
1610 | |
---|
1611 | return True; |
---|
1612 | } |
---|
1613 | |
---|
1614 | /******************************************************************* |
---|
1615 | Encode a blob of data using the schannel alogrithm, also produceing |
---|
1616 | a checksum over the original data. We currently only support |
---|
1617 | signing and sealing togeather - the signing-only code is close, but not |
---|
1618 | quite compatible with what MS does. |
---|
1619 | ********************************************************************/ |
---|
1620 | |
---|
1621 | void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, |
---|
1622 | enum schannel_direction direction, |
---|
1623 | RPC_AUTH_SCHANNEL_CHK * verf, |
---|
1624 | char *data, size_t data_len) |
---|
1625 | { |
---|
1626 | uchar digest_final[16]; |
---|
1627 | uchar confounder[8]; |
---|
1628 | uchar seq_num[8]; |
---|
1629 | static const uchar nullbytes[8] = { 0, }; |
---|
1630 | |
---|
1631 | static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE; |
---|
1632 | static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE; |
---|
1633 | const uchar *schannel_sig = NULL; |
---|
1634 | |
---|
1635 | DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); |
---|
1636 | |
---|
1637 | if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { |
---|
1638 | schannel_sig = schannel_seal_sig; |
---|
1639 | } else { |
---|
1640 | schannel_sig = schannel_sign_sig; |
---|
1641 | } |
---|
1642 | |
---|
1643 | /* fill the 'confounder' with random data */ |
---|
1644 | generate_random_buffer(confounder, sizeof(confounder)); |
---|
1645 | |
---|
1646 | dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key)); |
---|
1647 | |
---|
1648 | RSIVAL(seq_num, 0, a->seq_num); |
---|
1649 | |
---|
1650 | switch (direction) { |
---|
1651 | case SENDER_IS_INITIATOR: |
---|
1652 | SIVAL(seq_num, 4, 0x80); |
---|
1653 | break; |
---|
1654 | case SENDER_IS_ACCEPTOR: |
---|
1655 | SIVAL(seq_num, 4, 0x0); |
---|
1656 | break; |
---|
1657 | } |
---|
1658 | |
---|
1659 | dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num)); |
---|
1660 | |
---|
1661 | init_rpc_auth_schannel_chk(verf, schannel_sig, nullbytes, |
---|
1662 | seq_num, confounder); |
---|
1663 | |
---|
1664 | /* produce a digest of the packet to prove it's legit (before we seal it) */ |
---|
1665 | schannel_digest(a, auth_level, verf, data, data_len, digest_final); |
---|
1666 | memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest)); |
---|
1667 | |
---|
1668 | if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { |
---|
1669 | uchar sealing_key[16]; |
---|
1670 | |
---|
1671 | /* get the key to encode the data with */ |
---|
1672 | schannel_get_sealing_key(a, verf, sealing_key); |
---|
1673 | |
---|
1674 | /* encode the verification data */ |
---|
1675 | dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder)); |
---|
1676 | SamOEMhash(verf->confounder, sealing_key, 8); |
---|
1677 | |
---|
1678 | dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder)); |
---|
1679 | |
---|
1680 | /* encode the packet payload */ |
---|
1681 | dump_data_pw("data:\n", (const unsigned char *)data, data_len); |
---|
1682 | SamOEMhash((unsigned char *)data, sealing_key, data_len); |
---|
1683 | dump_data_pw("data_enc:\n", (const unsigned char *)data, data_len); |
---|
1684 | } |
---|
1685 | |
---|
1686 | /* encode the sequence number (key based on packet digest) */ |
---|
1687 | /* needs to be done after the sealing, as the original version |
---|
1688 | is used in the sealing stuff... */ |
---|
1689 | schannel_deal_with_seq_num(a, verf); |
---|
1690 | |
---|
1691 | return; |
---|
1692 | } |
---|
1693 | |
---|
1694 | /******************************************************************* |
---|
1695 | Decode a blob of data using the schannel alogrithm, also verifiying |
---|
1696 | a checksum over the original data. We currently can verify signed messages, |
---|
1697 | as well as decode sealed messages |
---|
1698 | ********************************************************************/ |
---|
1699 | |
---|
1700 | BOOL schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, |
---|
1701 | enum schannel_direction direction, |
---|
1702 | RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len) |
---|
1703 | { |
---|
1704 | uchar digest_final[16]; |
---|
1705 | |
---|
1706 | static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE; |
---|
1707 | static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE; |
---|
1708 | const uchar *schannel_sig = NULL; |
---|
1709 | |
---|
1710 | uchar seq_num[8]; |
---|
1711 | |
---|
1712 | DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); |
---|
1713 | |
---|
1714 | if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { |
---|
1715 | schannel_sig = schannel_seal_sig; |
---|
1716 | } else { |
---|
1717 | schannel_sig = schannel_sign_sig; |
---|
1718 | } |
---|
1719 | |
---|
1720 | /* Create the expected sequence number for comparison */ |
---|
1721 | RSIVAL(seq_num, 0, a->seq_num); |
---|
1722 | |
---|
1723 | switch (direction) { |
---|
1724 | case SENDER_IS_INITIATOR: |
---|
1725 | SIVAL(seq_num, 4, 0x80); |
---|
1726 | break; |
---|
1727 | case SENDER_IS_ACCEPTOR: |
---|
1728 | SIVAL(seq_num, 4, 0x0); |
---|
1729 | break; |
---|
1730 | } |
---|
1731 | |
---|
1732 | DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); |
---|
1733 | dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key)); |
---|
1734 | |
---|
1735 | dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num)); |
---|
1736 | |
---|
1737 | /* extract the sequence number (key based on supplied packet digest) */ |
---|
1738 | /* needs to be done before the sealing, as the original version |
---|
1739 | is used in the sealing stuff... */ |
---|
1740 | schannel_deal_with_seq_num(a, verf); |
---|
1741 | |
---|
1742 | if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) { |
---|
1743 | /* don't even bother with the below if the sequence number is out */ |
---|
1744 | /* The sequence number is MD5'ed with a key based on the whole-packet |
---|
1745 | digest, as supplied by the client. We check that it's a valid |
---|
1746 | checksum after the decode, below |
---|
1747 | */ |
---|
1748 | DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n")); |
---|
1749 | dump_data(2, (const char*)verf->seq_num, sizeof(verf->seq_num)); |
---|
1750 | DEBUG(2, ("should be:\n")); |
---|
1751 | dump_data(2, (const char*)seq_num, sizeof(seq_num)); |
---|
1752 | |
---|
1753 | return False; |
---|
1754 | } |
---|
1755 | |
---|
1756 | if (memcmp(verf->sig, schannel_sig, sizeof(verf->sig))) { |
---|
1757 | /* Validate that the other end sent the expected header */ |
---|
1758 | DEBUG(2, ("schannel_decode: FAILED: packet header:\n")); |
---|
1759 | dump_data(2, (const char*)verf->sig, sizeof(verf->sig)); |
---|
1760 | DEBUG(2, ("should be:\n")); |
---|
1761 | dump_data(2, (const char*)schannel_sig, sizeof(schannel_sig)); |
---|
1762 | return False; |
---|
1763 | } |
---|
1764 | |
---|
1765 | if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { |
---|
1766 | uchar sealing_key[16]; |
---|
1767 | |
---|
1768 | /* get the key to extract the data with */ |
---|
1769 | schannel_get_sealing_key(a, verf, sealing_key); |
---|
1770 | |
---|
1771 | /* extract the verification data */ |
---|
1772 | dump_data_pw("verf->confounder:\n", verf->confounder, |
---|
1773 | sizeof(verf->confounder)); |
---|
1774 | SamOEMhash(verf->confounder, sealing_key, 8); |
---|
1775 | |
---|
1776 | dump_data_pw("verf->confounder_dec:\n", verf->confounder, |
---|
1777 | sizeof(verf->confounder)); |
---|
1778 | |
---|
1779 | /* extract the packet payload */ |
---|
1780 | dump_data_pw("data :\n", (const unsigned char *)data, data_len); |
---|
1781 | SamOEMhash((unsigned char *)data, sealing_key, data_len); |
---|
1782 | dump_data_pw("datadec:\n", (const unsigned char *)data, data_len); |
---|
1783 | } |
---|
1784 | |
---|
1785 | /* digest includes 'data' after unsealing */ |
---|
1786 | schannel_digest(a, auth_level, verf, data, data_len, digest_final); |
---|
1787 | |
---|
1788 | dump_data_pw("Calculated digest:\n", digest_final, |
---|
1789 | sizeof(digest_final)); |
---|
1790 | dump_data_pw("verf->packet_digest:\n", verf->packet_digest, |
---|
1791 | sizeof(verf->packet_digest)); |
---|
1792 | |
---|
1793 | /* compare - if the client got the same result as us, then |
---|
1794 | it must know the session key */ |
---|
1795 | return (memcmp(digest_final, verf->packet_digest, |
---|
1796 | sizeof(verf->packet_digest)) == 0); |
---|
1797 | } |
---|
1798 | |
---|
1799 | /******************************************************************* |
---|
1800 | creates a new prs_struct containing a DATA_BLOB |
---|
1801 | ********************************************************************/ |
---|
1802 | BOOL prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx) |
---|
1803 | { |
---|
1804 | if (!prs_init( prs, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL )) |
---|
1805 | return False; |
---|
1806 | |
---|
1807 | |
---|
1808 | if (!prs_copy_data_in(prs, (char *)blob->data, blob->length)) |
---|
1809 | return False; |
---|
1810 | |
---|
1811 | return True; |
---|
1812 | } |
---|
1813 | |
---|
1814 | /******************************************************************* |
---|
1815 | return the contents of a prs_struct in a DATA_BLOB |
---|
1816 | ********************************************************************/ |
---|
1817 | BOOL prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx) |
---|
1818 | { |
---|
1819 | blob->length = prs_data_size(prs); |
---|
1820 | blob->data = (uint8 *)talloc_zero_size(mem_ctx, blob->length); |
---|
1821 | |
---|
1822 | /* set the pointer at the end of the buffer */ |
---|
1823 | prs_set_offset( prs, prs_data_size(prs) ); |
---|
1824 | |
---|
1825 | if (!prs_copy_all_data_out((char *)blob->data, prs)) |
---|
1826 | return False; |
---|
1827 | |
---|
1828 | return True; |
---|
1829 | } |
---|