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