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

Last change on this file was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

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