2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
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.
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.
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.
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.
29 #define DBGC_CLASS DBGC_RPC_PARSE
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
)
37 buffer
->string_at_end
= size
;
38 prs_init(&buffer
->prs
, size
, ctx
, MARSHALL
);
39 buffer
->struct_start
= prs_offset(&buffer
->prs
);
42 /*******************************************************************
43 Read/write a RPC_BUFFER struct.
44 ********************************************************************/
46 BOOL
prs_rpcbuffer(const char *desc
, prs_struct
*ps
, int depth
, RPC_BUFFER
*buffer
)
48 prs_debug(ps
, depth
, desc
, "prs_rpcbuffer");
52 if (UNMARSHALLING(ps
)) {
54 buffer
->string_at_end
=0;
56 if (!prs_uint32("size", ps
, depth
, &buffer
->size
))
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.
64 if (!prs_init(&buffer
->prs
, buffer
->size
, prs_get_mem_context(ps
), UNMARSHALL
))
67 if (!prs_append_some_prs_data(&buffer
->prs
, ps
, prs_offset(ps
), buffer
->size
))
70 if (!prs_set_offset(&buffer
->prs
, 0))
73 if (!prs_set_offset(ps
, buffer
->size
+prs_offset(ps
)))
76 buffer
->string_at_end
=buffer
->size
;
83 if (!prs_uint32("size", ps
, depth
, &buffer
->size
))
86 if (!prs_append_some_prs_data(ps
, &buffer
->prs
, 0, buffer
->size
))
92 /* We have finished with the data in buffer->prs - free it. */
93 prs_mem_free(&buffer
->prs
);
99 /*******************************************************************
100 Read/write an RPC_BUFFER* struct.(allocate memory if unmarshalling)
101 ********************************************************************/
103 BOOL
prs_rpcbuffer_p(const char *desc
, prs_struct
*ps
, int depth
, RPC_BUFFER
**buffer
)
107 /* caputure the pointer value to stream */
109 data_p
= *buffer
? 0xf000baaa : 0;
111 if ( !prs_uint32("ptr", ps
, depth
, &data_p
))
114 /* we're done if there is no data */
119 if ( UNMARSHALLING(ps
) ) {
120 if ( !(*buffer
= PRS_ALLOC_MEM(ps
, RPC_BUFFER
, 1)) )
123 /* Marshalling case. - coverity paranoia - should already be ok if data_p != 0 */
129 return prs_rpcbuffer( desc
, ps
, depth
, *buffer
);
132 /****************************************************************************
133 Allocate more memory for a RPC_BUFFER.
134 ****************************************************************************/
136 BOOL
rpcbuf_alloc_size(RPC_BUFFER
*buffer
, uint32 buffer_size
)
142 /* if we don't need anything. don't do anything */
144 if ( buffer_size
== 0x0 )
153 /* damn, I'm doing the reverse operation of prs_grow() :) */
154 if (buffer_size
< prs_data_size(ps
))
157 extra_space
= buffer_size
- prs_data_size(ps
);
160 * save the offset and move to the end of the buffer
161 * prs_grow() checks the extra_space against the offset
163 old_offset
=prs_offset(ps
);
164 prs_set_offset(ps
, prs_data_size(ps
));
166 if (!prs_grow(ps
, extra_space
))
169 prs_set_offset(ps
, old_offset
);
171 buffer
->string_at_end
=prs_data_size(ps
);
176 /*******************************************************************
177 move a BUFFER from the query to the reply.
178 As the data pointers in RPC_BUFFER are malloc'ed, not talloc'ed,
179 this is ok. This is an OPTIMIZATION and is not strictly neccessary.
180 Clears the memory to zero also.
181 ********************************************************************/
183 void rpcbuf_move(RPC_BUFFER
*src
, RPC_BUFFER
**dest
)
190 prs_switch_type( &src
->prs
, MARSHALL
);
192 if ( !prs_set_offset(&src
->prs
, 0) )
195 prs_force_dynamic( &src
->prs
);
196 prs_mem_clear( &src
->prs
);
201 /*******************************************************************
202 Get the size of a BUFFER struct.
203 ********************************************************************/
205 uint32
rpcbuf_get_size(RPC_BUFFER
*buffer
)
207 return (buffer
->size
);
211 /*******************************************************************
212 * write a UNICODE string and its relative pointer.
213 * used by all the RPC structs passing a buffer
215 * As I'm a nice guy, I'm forcing myself to explain this code.
216 * MS did a good job in the overall spoolss code except in some
217 * functions where they are passing the API buffer directly in the
218 * RPC request/reply. That's to maintain compatiility at the API level.
219 * They could have done it the good way the first time.
221 * So what happen is: the strings are written at the buffer's end,
222 * in the reverse order of the original structure. Some pointers to
223 * the strings are also in the buffer. Those are relative to the
226 * If you don't understand or want to change that function,
227 * first get in touch with me: jfm@samba.org
229 ********************************************************************/
231 BOOL
smb_io_relstr(const char *desc
, RPC_BUFFER
*buffer
, int depth
, UNISTR
*string
)
233 prs_struct
*ps
=&buffer
->prs
;
235 if (MARSHALLING(ps
)) {
236 uint32 struct_offset
= prs_offset(ps
);
237 uint32 relative_offset
;
239 buffer
->string_at_end
-= (size_of_relative_string(string
) - 4);
240 if(!prs_set_offset(ps
, buffer
->string_at_end
))
244 * Win2k does not align strings in a buffer
245 * Tested against WinNT 4.0 SP 6a & 2k SP2 --jerry
250 buffer
->string_at_end
= prs_offset(ps
);
252 /* write the string */
253 if (!smb_io_unistr(desc
, string
, ps
, depth
))
256 if(!prs_set_offset(ps
, struct_offset
))
259 relative_offset
=buffer
->string_at_end
- buffer
->struct_start
;
260 /* write its offset */
261 if (!prs_uint32("offset", ps
, depth
, &relative_offset
))
267 /* read the offset */
268 if (!prs_uint32("offset", ps
, depth
, &(buffer
->string_at_end
)))
271 if (buffer
->string_at_end
== 0)
274 old_offset
= prs_offset(ps
);
275 if(!prs_set_offset(ps
, buffer
->string_at_end
+buffer
->struct_start
))
278 /* read the string */
279 if (!smb_io_unistr(desc
, string
, ps
, depth
))
282 if(!prs_set_offset(ps
, old_offset
))
288 /*******************************************************************
289 * write a array of UNICODE strings and its relative pointer.
290 * used by 2 RPC structs
291 ********************************************************************/
293 BOOL
smb_io_relarraystr(const char *desc
, RPC_BUFFER
*buffer
, int depth
, uint16
**string
)
297 prs_struct
*ps
=&buffer
->prs
;
299 if (MARSHALLING(ps
)) {
300 uint32 struct_offset
= prs_offset(ps
);
301 uint32 relative_offset
;
308 /* first write the last 0 */
309 buffer
->string_at_end
-= 2;
310 if(!prs_set_offset(ps
, buffer
->string_at_end
))
313 if(!prs_uint16("leading zero", ps
, depth
, &zero
))
316 while (p
&& (*p
!=0)) {
320 /* Yes this should be malloc not talloc. Don't change. */
322 chaine
.buffer
= (uint16
*)
323 SMB_MALLOC((q
-p
+1)*sizeof(uint16
));
324 if (chaine
.buffer
== NULL
)
327 memcpy(chaine
.buffer
, p
, (q
-p
+1)*sizeof(uint16
));
329 buffer
->string_at_end
-= (q
-p
+1)*sizeof(uint16
);
331 if(!prs_set_offset(ps
, buffer
->string_at_end
)) {
332 SAFE_FREE(chaine
.buffer
);
336 /* write the string */
337 if (!smb_io_unistr(desc
, &chaine
, ps
, depth
)) {
338 SAFE_FREE(chaine
.buffer
);
344 SAFE_FREE(chaine
.buffer
);
347 if(!prs_set_offset(ps
, struct_offset
))
350 relative_offset
=buffer
->string_at_end
- buffer
->struct_start
;
351 /* write its offset */
352 if (!prs_uint32("offset", ps
, depth
, &relative_offset
))
360 uint16
*chaine2
=NULL
;
363 size_t realloc_size
= 0;
367 /* read the offset */
368 if (!prs_uint32("offset", ps
, depth
, &buffer
->string_at_end
))
371 old_offset
= prs_offset(ps
);
372 if(!prs_set_offset(ps
, buffer
->string_at_end
+ buffer
->struct_start
))
376 if (!smb_io_unistr(desc
, &chaine
, ps
, depth
))
379 l_chaine
=str_len_uni(&chaine
);
381 /* we're going to add two more bytes here in case this
382 is the last string in the array and we need to add
383 an extra NULL for termination */
385 realloc_size
= (l_chaine2
+l_chaine
+2)*sizeof(uint16
);
387 /* Yes this should be realloc - it's freed below. JRA */
389 if((chaine2
=(uint16
*)SMB_REALLOC(chaine2
, realloc_size
)) == NULL
) {
392 memcpy(chaine2
+l_chaine2
, chaine
.buffer
, (l_chaine
+1)*sizeof(uint16
));
393 l_chaine2
+=l_chaine
+1;
396 } while(l_chaine
!=0);
398 /* the end should be bould NULL terminated so add
399 the second one here */
402 chaine2
[l_chaine2
] = '\0';
403 *string
=(uint16
*)TALLOC_MEMDUP(prs_get_mem_context(ps
),chaine2
,realloc_size
);
407 if(!prs_set_offset(ps
, old_offset
))
413 /*******************************************************************
414 Parse a DEVMODE structure and its relative pointer.
415 ********************************************************************/
417 BOOL
smb_io_relsecdesc(const char *desc
, RPC_BUFFER
*buffer
, int depth
, SEC_DESC
**secdesc
)
419 prs_struct
*ps
= &buffer
->prs
;
421 prs_debug(ps
, depth
, desc
, "smb_io_relsecdesc");
424 if (MARSHALLING(ps
)) {
425 uint32 struct_offset
= prs_offset(ps
);
426 uint32 relative_offset
;
430 if (!prs_uint32("offset", ps
, depth
, &relative_offset
))
435 if (*secdesc
!= NULL
) {
436 buffer
->string_at_end
-= sec_desc_size(*secdesc
);
438 if(!prs_set_offset(ps
, buffer
->string_at_end
))
440 /* write the secdesc */
441 if (!sec_io_desc(desc
, secdesc
, ps
, depth
))
444 if(!prs_set_offset(ps
, struct_offset
))
448 relative_offset
=buffer
->string_at_end
- buffer
->struct_start
;
449 /* write its offset */
451 if (!prs_uint32("offset", ps
, depth
, &relative_offset
))
456 /* read the offset */
457 if (!prs_uint32("offset", ps
, depth
, &buffer
->string_at_end
))
460 old_offset
= prs_offset(ps
);
461 if(!prs_set_offset(ps
, buffer
->string_at_end
+ buffer
->struct_start
))
465 if (!sec_io_desc(desc
, secdesc
, ps
, depth
))
468 if(!prs_set_offset(ps
, old_offset
))
476 /*******************************************************************
477 * return the length of a UNICODE string in number of char, includes:
479 * - the relative pointer size
480 ********************************************************************/
482 uint32
size_of_relative_string(UNISTR
*string
)
486 size
=str_len_uni(string
); /* the string length */
487 size
=size
+1; /* add the trailing zero */
488 size
=size
*2; /* convert in char */
489 size
=size
+4; /* add the size of the ptr */
493 * Do not include alignment as Win2k does not align relative
494 * strings within a buffer --jerry
496 /* Ensure size is 4 byte multiple (prs_align is being called...). */
497 /* size += ((4 - (size & 3)) & 3); */