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