Memory leaks and other fixes found by Coverity
[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 bool 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
48 bool 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
105 bool 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
138 bool 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
185 void 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
207 uint32 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
233 bool 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
295 bool 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
424 bool 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, NULL, 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
489 uint32 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