ae73c35c0a55f26734df34e48d3dde1de2576191
[ira/wip.git] / source3 / rpc_parse / parse_spoolss.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-2000,
5  *  Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
6  *  Copyright (C) Jean François Micouleau      1998-2000,
7  *  Copyright (C) Gerald Carter                2000-2002,
8  *  Copyright (C) Tim Potter                   2001-2002.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 3 of the License, or
13  *  (at your option) any later version.
14  *  
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *  
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "includes.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_RPC_PARSE
28
29
30 /*******************************************************************
31 This should be moved in a more generic lib.
32 ********************************************************************/  
33
34 bool spoolss_io_system_time(const char *desc, prs_struct *ps, int depth, SYSTEMTIME *systime)
35 {
36         if(!prs_uint16("year", ps, depth, &systime->year))
37                 return False;
38         if(!prs_uint16("month", ps, depth, &systime->month))
39                 return False;
40         if(!prs_uint16("dayofweek", ps, depth, &systime->dayofweek))
41                 return False;
42         if(!prs_uint16("day", ps, depth, &systime->day))
43                 return False;
44         if(!prs_uint16("hour", ps, depth, &systime->hour))
45                 return False;
46         if(!prs_uint16("minute", ps, depth, &systime->minute))
47                 return False;
48         if(!prs_uint16("second", ps, depth, &systime->second))
49                 return False;
50         if(!prs_uint16("milliseconds", ps, depth, &systime->milliseconds))
51                 return False;
52
53         return True;
54 }
55
56 /*******************************************************************
57 ********************************************************************/  
58
59 bool make_systemtime(SYSTEMTIME *systime, struct tm *unixtime)
60 {
61         systime->year=unixtime->tm_year+1900;
62         systime->month=unixtime->tm_mon+1;
63         systime->dayofweek=unixtime->tm_wday;
64         systime->day=unixtime->tm_mday;
65         systime->hour=unixtime->tm_hour;
66         systime->minute=unixtime->tm_min;
67         systime->second=unixtime->tm_sec;
68         systime->milliseconds=0;
69
70         return True;
71 }
72
73 /*******************************************************************
74  * read or write a DEVICEMODE struct.
75  * on reading allocate memory for the private member
76  ********************************************************************/
77
78 #define DM_NUM_OPTIONAL_FIELDS          8
79
80 bool spoolss_io_devmode(const char *desc, prs_struct *ps, int depth, DEVICEMODE *devmode)
81 {
82         int available_space;            /* size of the device mode left to parse */
83                                         /* only important on unmarshalling       */
84         int i = 0;
85         uint16 *unistr_buffer;
86         int j;
87                                         
88         struct optional_fields {
89                 fstring         name;
90                 uint32*         field;
91         } opt_fields[DM_NUM_OPTIONAL_FIELDS] = {
92                 { "icmmethod",          NULL },
93                 { "icmintent",          NULL },
94                 { "mediatype",          NULL },
95                 { "dithertype",         NULL },
96                 { "reserved1",          NULL },
97                 { "reserved2",          NULL },
98                 { "panningwidth",       NULL },
99                 { "panningheight",      NULL }
100         };
101
102         /* assign at run time to keep non-gcc compilers happy */
103
104         opt_fields[0].field = &devmode->icmmethod;
105         opt_fields[1].field = &devmode->icmintent;
106         opt_fields[2].field = &devmode->mediatype;
107         opt_fields[3].field = &devmode->dithertype;
108         opt_fields[4].field = &devmode->reserved1;
109         opt_fields[5].field = &devmode->reserved2;
110         opt_fields[6].field = &devmode->panningwidth;
111         opt_fields[7].field = &devmode->panningheight;
112                 
113         
114         prs_debug(ps, depth, desc, "spoolss_io_devmode");
115         depth++;
116
117         if (UNMARSHALLING(ps)) {
118                 devmode->devicename.buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
119                 if (devmode->devicename.buffer == NULL)
120                         return False;
121                 unistr_buffer = devmode->devicename.buffer;
122         }
123         else {
124                 /* devicename is a static sized string but the buffer we set is not */
125                 unistr_buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
126                 memset( unistr_buffer, 0x0, MAXDEVICENAME );
127                 for ( j=0; devmode->devicename.buffer[j]; j++ )
128                         unistr_buffer[j] = devmode->devicename.buffer[j];
129         }
130                 
131         if (!prs_uint16uni(True,"devicename", ps, depth, unistr_buffer, MAXDEVICENAME))
132                 return False;
133         
134         if (!prs_uint16("specversion",      ps, depth, &devmode->specversion))
135                 return False;
136                 
137         if (!prs_uint16("driverversion",    ps, depth, &devmode->driverversion))
138                 return False;
139         if (!prs_uint16("size",             ps, depth, &devmode->size))
140                 return False;
141         if (!prs_uint16("driverextra",      ps, depth, &devmode->driverextra))
142                 return False;
143         if (!prs_uint32("fields",           ps, depth, &devmode->fields))
144                 return False;
145         if (!prs_uint16("orientation",      ps, depth, &devmode->orientation))
146                 return False;
147         if (!prs_uint16("papersize",        ps, depth, &devmode->papersize))
148                 return False;
149         if (!prs_uint16("paperlength",      ps, depth, &devmode->paperlength))
150                 return False;
151         if (!prs_uint16("paperwidth",       ps, depth, &devmode->paperwidth))
152                 return False;
153         if (!prs_uint16("scale",            ps, depth, &devmode->scale))
154                 return False;
155         if (!prs_uint16("copies",           ps, depth, &devmode->copies))
156                 return False;
157         if (!prs_uint16("defaultsource",    ps, depth, &devmode->defaultsource))
158                 return False;
159         if (!prs_uint16("printquality",     ps, depth, &devmode->printquality))
160                 return False;
161         if (!prs_uint16("color",            ps, depth, &devmode->color))
162                 return False;
163         if (!prs_uint16("duplex",           ps, depth, &devmode->duplex))
164                 return False;
165         if (!prs_uint16("yresolution",      ps, depth, &devmode->yresolution))
166                 return False;
167         if (!prs_uint16("ttoption",         ps, depth, &devmode->ttoption))
168                 return False;
169         if (!prs_uint16("collate",          ps, depth, &devmode->collate))
170                 return False;
171
172         if (UNMARSHALLING(ps)) {
173                 devmode->formname.buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
174                 if (devmode->formname.buffer == NULL)
175                         return False;
176                 unistr_buffer = devmode->formname.buffer;
177         }
178         else {
179                 /* devicename is a static sized string but the buffer we set is not */
180                 unistr_buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
181                 memset( unistr_buffer, 0x0, MAXDEVICENAME );
182                 for ( j=0; devmode->formname.buffer[j]; j++ )
183                         unistr_buffer[j] = devmode->formname.buffer[j];
184         }
185         
186         if (!prs_uint16uni(True, "formname",  ps, depth, unistr_buffer, MAXDEVICENAME))
187                 return False;
188         if (!prs_uint16("logpixels",        ps, depth, &devmode->logpixels))
189                 return False;
190         if (!prs_uint32("bitsperpel",       ps, depth, &devmode->bitsperpel))
191                 return False;
192         if (!prs_uint32("pelswidth",        ps, depth, &devmode->pelswidth))
193                 return False;
194         if (!prs_uint32("pelsheight",       ps, depth, &devmode->pelsheight))
195                 return False;
196         if (!prs_uint32("displayflags",     ps, depth, &devmode->displayflags))
197                 return False;
198         if (!prs_uint32("displayfrequency", ps, depth, &devmode->displayfrequency))
199                 return False;
200         /* 
201          * every device mode I've ever seen on the wire at least has up 
202          * to the displayfrequency field.   --jerry (05-09-2002)
203          */
204          
205         /* add uint32's + uint16's + two UNICODE strings */
206          
207         available_space = devmode->size - (sizeof(uint32)*6 + sizeof(uint16)*18 + sizeof(uint16)*64);
208         
209         /* Sanity check - we only have uint32's left tp parse */
210         
211         if ( available_space && ((available_space % sizeof(uint32)) != 0) ) {
212                 DEBUG(0,("spoolss_io_devmode: available_space [%d] no in multiple of 4 bytes (size = %d)!\n",
213                         available_space, devmode->size));
214                 DEBUG(0,("spoolss_io_devmode: please report to samba-technical@samba.org!\n"));
215                 return False;
216         }
217
218         /* 
219          * Conditional parsing.  Assume that the DeviceMode has been 
220          * zero'd by the caller. 
221          */
222         
223         while ((available_space > 0)  && (i < DM_NUM_OPTIONAL_FIELDS))
224         {
225                 DEBUG(11, ("spoolss_io_devmode: [%d] bytes left to parse in devmode\n", available_space));
226                 if (!prs_uint32(opt_fields[i].name, ps, depth, opt_fields[i].field))
227                         return False;
228                 available_space -= sizeof(uint32);
229                 i++;
230         }        
231         
232         /* Sanity Check - we should no available space at this point unless 
233            MS changes the device mode structure */
234                 
235         if (available_space) {
236                 DEBUG(0,("spoolss_io_devmode: I've parsed all I know and there is still stuff left|\n"));
237                 DEBUG(0,("spoolss_io_devmode: available_space = [%d], devmode_size = [%d]!\n",
238                         available_space, devmode->size));
239                 DEBUG(0,("spoolss_io_devmode: please report to samba-technical@samba.org!\n"));
240                 return False;
241         }
242
243
244         if (devmode->driverextra!=0) {
245                 if (UNMARSHALLING(ps)) {
246                         devmode->dev_private=PRS_ALLOC_MEM(ps, uint8, devmode->driverextra);
247                         if(devmode->dev_private == NULL)
248                                 return False;
249                         DEBUG(7,("spoolss_io_devmode: allocated memory [%d] for dev_private\n",devmode->driverextra)); 
250                 }
251                         
252                 DEBUG(7,("spoolss_io_devmode: parsing [%d] bytes of dev_private\n",devmode->driverextra));
253                 if (!prs_uint8s(False, "dev_private",  ps, depth,
254                                 devmode->dev_private, devmode->driverextra))
255                         return False;
256         }
257
258         return True;
259 }
260
261 /*******************************************************************
262  * return the length of a uint32 (obvious, but the code is clean)
263  ********************************************************************/
264
265 static uint32 size_of_uint32(uint32 *value)
266 {
267         return (sizeof(*value));
268 }
269
270 /*******************************************************************
271 return the size required by a struct in the stream
272 ********************************************************************/  
273 uint32 spoolss_size_printer_enum_values(PRINTER_ENUM_VALUES *p)
274 {
275         uint32  size = 0; 
276         
277         if (!p)
278                 return 0;
279         
280         /* uint32(offset) + uint32(length) + length) */
281         size += (size_of_uint32(&p->value_len)*2) + p->value_len;
282         size += (size_of_uint32(&p->data_len)*2) + p->data_len + (p->data_len%2) ;
283         
284         size += size_of_uint32(&p->type);
285                        
286         return size;
287 }
288
289 /*******************************************************************
290  make a BUFFER5 struct from a uint16*
291  ******************************************************************/
292
293 bool make_spoolss_buffer5(TALLOC_CTX *mem_ctx, BUFFER5 *buf5, uint32 len, uint16 *src)
294 {
295
296         buf5->buf_len = len;
297         if (src) {
298                 if (len) {
299                         if((buf5->buffer=(uint16*)TALLOC_MEMDUP(mem_ctx, src, sizeof(uint16)*len)) == NULL) {
300                                 DEBUG(0,("make_spoolss_buffer5: Unable to malloc memory for buffer!\n"));
301                                 return False;
302                         }
303                 } else {
304                         buf5->buffer = NULL;
305                 }
306         } else {
307                 buf5->buffer=NULL;
308         }
309         
310         return True;
311 }
312
313 /*******************************************************************
314 ********************************************************************/  
315
316 bool make_spoolss_q_enumprinterdataex(SPOOL_Q_ENUMPRINTERDATAEX *q_u,
317                                       const POLICY_HND *hnd, const char *key,
318                                       uint32 size)
319 {
320         memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
321         init_unistr2(&q_u->key, key, UNI_STR_TERMINATE);
322         q_u->size = size;
323
324         return True;
325 }
326
327 /*******************************************************************
328  * read a structure.
329  ********************************************************************/  
330
331 bool spoolss_io_q_enumprinterdataex(const char *desc, SPOOL_Q_ENUMPRINTERDATAEX *q_u, prs_struct *ps, int depth)
332 {
333         prs_debug(ps, depth, desc, "spoolss_io_q_enumprinterdataex");
334         depth++;
335
336         if(!prs_align(ps))
337                 return False;
338         if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
339                 return False;
340                 
341         if(!smb_io_unistr2("", &q_u->key, True, ps, depth))
342                 return False;
343
344         if(!prs_align(ps))
345                 return False;
346         
347         if(!prs_uint32("size", ps, depth, &q_u->size))
348                 return False;
349
350         return True;
351 }
352
353 /*******************************************************************
354 ********************************************************************/  
355
356 static bool spoolss_io_printer_enum_values_ctr(const char *desc, prs_struct *ps, 
357                                 PRINTER_ENUM_VALUES_CTR *ctr, int depth)
358 {
359         int     i;
360         uint32  valuename_offset,
361                 data_offset,
362                 current_offset;
363         const uint32 basic_unit = 20; /* size of static portion of enum_values */
364
365         prs_debug(ps, depth, desc, "spoolss_io_printer_enum_values_ctr");
366         depth++;        
367
368         /* 
369          * offset data begins at 20 bytes per structure * size_of_array.
370          * Don't forget the uint32 at the beginning 
371          * */
372         
373         current_offset = basic_unit * ctr->size_of_array;
374         
375         /* first loop to write basic enum_value information */
376         
377         if (UNMARSHALLING(ps) && ctr->size_of_array) {
378                 ctr->values = PRS_ALLOC_MEM(ps, PRINTER_ENUM_VALUES, ctr->size_of_array);
379                 if (!ctr->values)
380                         return False;
381         }
382
383         for (i=0; i<ctr->size_of_array; i++) {
384                 uint32 base_offset, return_offset;
385
386                 base_offset = prs_offset(ps);
387
388                 valuename_offset = current_offset;
389                 if (!prs_uint32("valuename_offset", ps, depth, &valuename_offset))
390                         return False;
391
392                 /* Read or write the value. */
393
394                 return_offset = prs_offset(ps);
395
396                 if (!prs_set_offset(ps, base_offset + valuename_offset)) {
397                         return False;
398                 }
399
400                 if (!prs_unistr("valuename", ps, depth, &ctr->values[i].valuename))
401                         return False;
402
403                 /* And go back. */
404                 if (!prs_set_offset(ps, return_offset))
405                         return False;
406
407                 if (!prs_uint32("value_len", ps, depth, &ctr->values[i].value_len))
408                         return False;
409         
410                 if (!prs_uint32("type", ps, depth, &ctr->values[i].type))
411                         return False;
412         
413                 data_offset = ctr->values[i].value_len + valuename_offset;
414                 
415                 if (!prs_uint32("data_offset", ps, depth, &data_offset))
416                         return False;
417
418                 if (!prs_uint32("data_len", ps, depth, &ctr->values[i].data_len))
419                         return False;
420                         
421                 /* Read or write the data. */
422
423                 return_offset = prs_offset(ps);
424
425                 if (!prs_set_offset(ps, base_offset + data_offset)) {
426                         return False;
427                 }
428
429                 if ( ctr->values[i].data_len ) {
430                         if ( UNMARSHALLING(ps) ) {
431                                 ctr->values[i].data = PRS_ALLOC_MEM(ps, uint8, ctr->values[i].data_len);
432                                 if (!ctr->values[i].data)
433                                         return False;
434                         }
435                         if (!prs_uint8s(False, "data", ps, depth, ctr->values[i].data, ctr->values[i].data_len))
436                                 return False;
437                 }
438
439                 current_offset  = data_offset + ctr->values[i].data_len - basic_unit;
440                 /* account for 2 byte alignment */
441                 current_offset += (current_offset % 2);
442
443                 /* Remember how far we got. */
444                 data_offset = prs_offset(ps);
445
446                 /* And go back. */
447                 if (!prs_set_offset(ps, return_offset))
448                         return False;
449
450         }
451
452         /* Go to the last data offset we got to. */
453
454         if (!prs_set_offset(ps, data_offset))
455                 return False;
456
457         /* And ensure we're 2 byte aligned. */
458
459         if ( !prs_align_uint16(ps) )
460                 return False;
461
462         return True;    
463 }
464
465 /*******************************************************************
466  * write a structure.
467  ********************************************************************/  
468
469 bool spoolss_io_r_enumprinterdataex(const char *desc, SPOOL_R_ENUMPRINTERDATAEX *r_u, prs_struct *ps, int depth)
470 {
471         uint32 data_offset, end_offset;
472         prs_debug(ps, depth, desc, "spoolss_io_r_enumprinterdataex");
473         depth++;
474
475         if(!prs_align(ps))
476                 return False;
477
478         if (!prs_uint32("size", ps, depth, &r_u->ctr.size))
479                 return False;
480
481         data_offset = prs_offset(ps);
482
483         if (!prs_set_offset(ps, data_offset + r_u->ctr.size))
484                 return False;
485
486         if(!prs_align(ps))
487                 return False;
488
489         if(!prs_uint32("needed",     ps, depth, &r_u->needed))
490                 return False;
491
492         if(!prs_uint32("returned",   ps, depth, &r_u->returned))
493                 return False;
494
495         if(!prs_werror("status",     ps, depth, &r_u->status))
496                 return False;
497
498         r_u->ctr.size_of_array = r_u->returned;
499
500         end_offset = prs_offset(ps);
501
502         if (!prs_set_offset(ps, data_offset))
503                 return False;
504
505         if (r_u->ctr.size)
506                 if (!spoolss_io_printer_enum_values_ctr("", ps, &r_u->ctr, depth ))
507                         return False;
508
509         if (!prs_set_offset(ps, end_offset))
510                 return False;
511         return True;
512 }