b5177cc6343e754d545c6b863e398b4b80e5b23c
[kai/samba.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, 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 **********************************************************************/
33 void 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
47 bool 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
104 bool 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
137 bool 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
184 void 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
206 uint32 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
232 bool 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
294 bool 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
423 bool 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, NULL, 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
488 uint32 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