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