source: branches/samba-3.2.x/source/rpc_parse/parse_buffer.c

Last change on this file was 133, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.0pre3

File size: 12.9 KB
Line 
1/*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 *
5 * Copyright (C) Andrew Tridgell 1992-2000,
6 * Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
7 * Copyright (C) Jean François Micouleau 1998-2000,
8 * Copyright (C) Gerald Carter 2000-2005,
9 * Copyright (C) Tim Potter 2001-2002.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 */
24
25#include "includes.h"
26
27#undef DBGC_CLASS
28#define DBGC_CLASS DBGC_RPC_PARSE
29
30/**********************************************************************
31 Initialize a new spoolss buff for use by a client rpc
32**********************************************************************/
33void rpcbuf_init(RPC_BUFFER *buffer, uint32 size, TALLOC_CTX *ctx)
34{
35 buffer->size = size;
36 buffer->string_at_end = size;
37 if (prs_init(&buffer->prs, size, ctx, MARSHALL))
38 buffer->struct_start = prs_offset(&buffer->prs);
39 else
40 buffer->struct_start = 0;
41}
42
43/*******************************************************************
44 Read/write a RPC_BUFFER struct.
45********************************************************************/
46
47bool prs_rpcbuffer(const char *desc, prs_struct *ps, int depth, RPC_BUFFER *buffer)
48{
49 prs_debug(ps, depth, desc, "prs_rpcbuffer");
50 depth++;
51
52 /* reading */
53 if (UNMARSHALLING(ps)) {
54 buffer->size=0;
55 buffer->string_at_end=0;
56
57 if (!prs_uint32("size", ps, depth, &buffer->size))
58 return False;
59
60 /*
61 * JRA. I'm not sure if the data in here is in big-endian format if
62 * the client is big-endian. Leave as default (little endian) for now.
63 */
64
65 if (!prs_init(&buffer->prs, buffer->size, prs_get_mem_context(ps), UNMARSHALL))
66 return False;
67
68 if (!prs_append_some_prs_data(&buffer->prs, ps, prs_offset(ps), buffer->size))
69 return False;
70
71 if (!prs_set_offset(&buffer->prs, 0))
72 return False;
73
74 if (!prs_set_offset(ps, buffer->size+prs_offset(ps)))
75 return False;
76
77 buffer->string_at_end=buffer->size;
78
79 return True;
80 }
81 else {
82 bool ret = False;
83
84 if (!prs_uint32("size", ps, depth, &buffer->size))
85 goto out;
86
87 if (!prs_append_some_prs_data(ps, &buffer->prs, 0, buffer->size))
88 goto out;
89
90 ret = True;
91 out:
92
93 /* We have finished with the data in buffer->prs - free it. */
94 prs_mem_free(&buffer->prs);
95
96 return ret;
97 }
98}
99
100/*******************************************************************
101 Read/write an RPC_BUFFER* struct.(allocate memory if unmarshalling)
102********************************************************************/
103
104bool prs_rpcbuffer_p(const char *desc, prs_struct *ps, int depth, RPC_BUFFER **buffer)
105{
106 uint32 data_p;
107
108 /* caputure the pointer value to stream */
109
110 data_p = *buffer ? 0xf000baaa : 0;
111
112 if ( !prs_uint32("ptr", ps, depth, &data_p ))
113 return False;
114
115 /* we're done if there is no data */
116
117 if ( !data_p )
118 return True;
119
120 if ( UNMARSHALLING(ps) ) {
121 if ( !(*buffer = PRS_ALLOC_MEM(ps, RPC_BUFFER, 1)) )
122 return False;
123 } else {
124 /* Marshalling case. - coverity paranoia - should already be ok if data_p != 0 */
125 if (!*buffer) {
126 return True;
127 }
128 }
129
130 return prs_rpcbuffer( desc, ps, depth, *buffer);
131}
132
133/****************************************************************************
134 Allocate more memory for a RPC_BUFFER.
135****************************************************************************/
136
137bool rpcbuf_alloc_size(RPC_BUFFER *buffer, uint32 buffer_size)
138{
139 prs_struct *ps;
140 uint32 extra_space;
141 uint32 old_offset;
142
143 /* if we don't need anything. don't do anything */
144
145 if ( buffer_size == 0x0 )
146 return True;
147
148 if (!buffer) {
149 return False;
150 }
151
152 ps= &buffer->prs;
153
154 /* damn, I'm doing the reverse operation of prs_grow() :) */
155 if (buffer_size < prs_data_size(ps))
156 extra_space=0;
157 else
158 extra_space = buffer_size - prs_data_size(ps);
159
160 /*
161 * save the offset and move to the end of the buffer
162 * prs_grow() checks the extra_space against the offset
163 */
164 old_offset=prs_offset(ps);
165 prs_set_offset(ps, prs_data_size(ps));
166
167 if (!prs_grow(ps, extra_space))
168 return False;
169
170 prs_set_offset(ps, old_offset);
171
172 buffer->string_at_end=prs_data_size(ps);
173
174 return True;
175}
176
177/*******************************************************************
178 move a BUFFER from the query to the reply.
179 As the data pointers in RPC_BUFFER are malloc'ed, not talloc'ed,
180 this is ok. This is an OPTIMIZATION and is not strictly neccessary.
181 Clears the memory to zero also.
182********************************************************************/
183
184void rpcbuf_move(RPC_BUFFER *src, RPC_BUFFER **dest)
185{
186 if ( !src ) {
187 *dest = NULL;
188 return;
189 }
190
191 prs_switch_type( &src->prs, MARSHALL );
192
193 if ( !prs_set_offset(&src->prs, 0) )
194 return;
195
196 prs_force_dynamic( &src->prs );
197 prs_mem_clear( &src->prs );
198
199 *dest = src;
200}
201
202/*******************************************************************
203 Get the size of a BUFFER struct.
204********************************************************************/
205
206uint32 rpcbuf_get_size(RPC_BUFFER *buffer)
207{
208 return (buffer->size);
209}
210
211
212/*******************************************************************
213 * write a UNICODE string and its relative pointer.
214 * used by all the RPC structs passing a buffer
215 *
216 * As I'm a nice guy, I'm forcing myself to explain this code.
217 * MS did a good job in the overall spoolss code except in some
218 * functions where they are passing the API buffer directly in the
219 * RPC request/reply. That's to maintain compatiility at the API level.
220 * They could have done it the good way the first time.
221 *
222 * So what happen is: the strings are written at the buffer's end,
223 * in the reverse order of the original structure. Some pointers to
224 * the strings are also in the buffer. Those are relative to the
225 * buffer's start.
226 *
227 * If you don't understand or want to change that function,
228 * first get in touch with me: jfm@samba.org
229 *
230 ********************************************************************/
231
232bool smb_io_relstr(const char *desc, RPC_BUFFER *buffer, int depth, UNISTR *string)
233{
234 prs_struct *ps=&buffer->prs;
235
236 if (MARSHALLING(ps)) {
237 uint32 struct_offset = prs_offset(ps);
238 uint32 relative_offset;
239
240 buffer->string_at_end -= (size_of_relative_string(string) - 4);
241 if(!prs_set_offset(ps, buffer->string_at_end))
242 return False;
243#if 0 /* JERRY */
244 /*
245 * Win2k does not align strings in a buffer
246 * Tested against WinNT 4.0 SP 6a & 2k SP2 --jerry
247 */
248 if (!prs_align(ps))
249 return False;
250#endif
251 buffer->string_at_end = prs_offset(ps);
252
253 /* write the string */
254 if (!smb_io_unistr(desc, string, ps, depth))
255 return False;
256
257 if(!prs_set_offset(ps, struct_offset))
258 return False;
259
260 relative_offset=buffer->string_at_end - buffer->struct_start;
261 /* write its offset */
262 if (!prs_uint32("offset", ps, depth, &relative_offset))
263 return False;
264 }
265 else {
266 uint32 old_offset;
267
268 /* read the offset */
269 if (!prs_uint32("offset", ps, depth, &(buffer->string_at_end)))
270 return False;
271
272 if (buffer->string_at_end == 0)
273 return True;
274
275 old_offset = prs_offset(ps);
276 if(!prs_set_offset(ps, buffer->string_at_end+buffer->struct_start))
277 return False;
278
279 /* read the string */
280 if (!smb_io_unistr(desc, string, ps, depth))
281 return False;
282
283 if(!prs_set_offset(ps, old_offset))
284 return False;
285 }
286 return True;
287}
288
289/*******************************************************************
290 * write a array of UNICODE strings and its relative pointer.
291 * used by 2 RPC structs
292 ********************************************************************/
293
294bool smb_io_relarraystr(const char *desc, RPC_BUFFER *buffer, int depth, uint16 **string)
295{
296 UNISTR chaine;
297
298 prs_struct *ps=&buffer->prs;
299
300 if (MARSHALLING(ps)) {
301 uint32 struct_offset = prs_offset(ps);
302 uint32 relative_offset;
303 uint16 *p;
304 uint16 *q;
305 uint16 zero=0;
306 p=*string;
307 q=*string;
308
309 /* first write the last 0 */
310 buffer->string_at_end -= 2;
311 if(!prs_set_offset(ps, buffer->string_at_end))
312 return False;
313
314 if(!prs_uint16("leading zero", ps, depth, &zero))
315 return False;
316
317 while (p && (*p!=0)) {
318 while (*q!=0)
319 q++;
320
321 /* Yes this should be malloc not talloc. Don't change. */
322
323 chaine.buffer = (uint16 *)
324 SMB_MALLOC((q-p+1)*sizeof(uint16));
325 if (chaine.buffer == NULL)
326 return False;
327
328 memcpy(chaine.buffer, p, (q-p+1)*sizeof(uint16));
329
330 buffer->string_at_end -= (q-p+1)*sizeof(uint16);
331
332 if(!prs_set_offset(ps, buffer->string_at_end)) {
333 SAFE_FREE(chaine.buffer);
334 return False;
335 }
336
337 /* write the string */
338 if (!smb_io_unistr(desc, &chaine, ps, depth)) {
339 SAFE_FREE(chaine.buffer);
340 return False;
341 }
342 q++;
343 p=q;
344
345 SAFE_FREE(chaine.buffer);
346 }
347
348 if(!prs_set_offset(ps, struct_offset))
349 return False;
350
351 relative_offset=buffer->string_at_end - buffer->struct_start;
352 /* write its offset */
353 if (!prs_uint32("offset", ps, depth, &relative_offset))
354 return False;
355
356 } else {
357
358 /* UNMARSHALLING */
359
360 uint32 old_offset;
361 uint16 *chaine2=NULL;
362 int l_chaine=0;
363 int l_chaine2=0;
364 size_t realloc_size = 0;
365
366 *string=NULL;
367
368 /* read the offset */
369 if (!prs_uint32("offset", ps, depth, &buffer->string_at_end))
370 return False;
371
372 old_offset = prs_offset(ps);
373 if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start))
374 return False;
375
376 do {
377 if (!smb_io_unistr(desc, &chaine, ps, depth)) {
378 SAFE_FREE(chaine2);
379 return False;
380 }
381
382 l_chaine=str_len_uni(&chaine);
383
384 /* we're going to add two more bytes here in case this
385 is the last string in the array and we need to add
386 an extra NULL for termination */
387 if (l_chaine > 0) {
388 realloc_size = (l_chaine2+l_chaine+2)*sizeof(uint16);
389
390 /* Yes this should be realloc - it's freed below. JRA */
391
392 if((chaine2=(uint16 *)SMB_REALLOC(chaine2, realloc_size)) == NULL) {
393 return False;
394 }
395 memcpy(chaine2+l_chaine2, chaine.buffer, (l_chaine+1)*sizeof(uint16));
396 l_chaine2+=l_chaine+1;
397 }
398
399 } while(l_chaine!=0);
400
401 /* the end should be bould NULL terminated so add
402 the second one here */
403 if (chaine2)
404 {
405 chaine2[l_chaine2] = '\0';
406 *string=(uint16 *)TALLOC_MEMDUP(prs_get_mem_context(ps),chaine2,realloc_size);
407 SAFE_FREE(chaine2);
408 if (!*string) {
409 return False;
410 }
411 }
412
413 if(!prs_set_offset(ps, old_offset))
414 return False;
415 }
416 return True;
417}
418
419/*******************************************************************
420 Parse a DEVMODE structure and its relative pointer.
421********************************************************************/
422
423bool smb_io_relsecdesc(const char *desc, RPC_BUFFER *buffer, int depth, SEC_DESC **secdesc)
424{
425 prs_struct *ps= &buffer->prs;
426
427 prs_debug(ps, depth, desc, "smb_io_relsecdesc");
428 depth++;
429
430 if (MARSHALLING(ps)) {
431 uint32 struct_offset = prs_offset(ps);
432 uint32 relative_offset;
433
434 if (! *secdesc) {
435 relative_offset = 0;
436 if (!prs_uint32("offset", ps, depth, &relative_offset))
437 return False;
438 return True;
439 }
440
441 if (*secdesc != NULL) {
442 buffer->string_at_end -= ndr_size_security_descriptor(*secdesc, 0);
443
444 if(!prs_set_offset(ps, buffer->string_at_end))
445 return False;
446 /* write the secdesc */
447 if (!sec_io_desc(desc, secdesc, ps, depth))
448 return False;
449
450 if(!prs_set_offset(ps, struct_offset))
451 return False;
452 }
453
454 relative_offset=buffer->string_at_end - buffer->struct_start;
455 /* write its offset */
456
457 if (!prs_uint32("offset", ps, depth, &relative_offset))
458 return False;
459 } else {
460 uint32 old_offset;
461
462 /* read the offset */
463 if (!prs_uint32("offset", ps, depth, &buffer->string_at_end))
464 return False;
465
466 old_offset = prs_offset(ps);
467 if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start))
468 return False;
469
470 /* read the sd */
471 if (!sec_io_desc(desc, secdesc, ps, depth))
472 return False;
473
474 if(!prs_set_offset(ps, old_offset))
475 return False;
476 }
477 return True;
478}
479
480
481
482/*******************************************************************
483 * return the length of a UNICODE string in number of char, includes:
484 * - the leading zero
485 * - the relative pointer size
486 ********************************************************************/
487
488uint32 size_of_relative_string(UNISTR *string)
489{
490 uint32 size=0;
491
492 size=str_len_uni(string); /* the string length */
493 size=size+1; /* add the trailing zero */
494 size=size*2; /* convert in char */
495 size=size+4; /* add the size of the ptr */
496
497#if 0 /* JERRY */
498 /*
499 * Do not include alignment as Win2k does not align relative
500 * strings within a buffer --jerry
501 */
502 /* Ensure size is 4 byte multiple (prs_align is being called...). */
503 /* size += ((4 - (size & 3)) & 3); */
504#endif
505
506 return size;
507}
508
Note: See TracBrowser for help on using the repository browser.