52320e6d28cdc7742c2b89072b9c96a22b7019ec
[ira/wip.git] / source3 / rpc_parse / parse_buffer.c
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, 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 **********************************************************************/
34 void 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
46 BOOL 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
103 BOOL 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
136 BOOL 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
183 void 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
205 uint32 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
231 BOOL 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
293 BOOL 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
420 BOOL 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
485 uint32 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