source: branches/samba-3.0/source/rpc_parse/parse_buffer.c

Last change on this file was 39, checked in by Paul Smedley, 18 years ago

Upgrade source to 3.0.25a

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