r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
[nivanova/samba-autobuild/.git] / source3 / registry / reg_printing.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Virtual Windows Registry Layer
4  *  Copyright (C) Gerald Carter                     2002-2005
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *  
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *  
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 /* Implementation of registry virtual views for printing information */
22
23 #include "includes.h"
24
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_RPC_SRV
27
28 /* registrt paths used in the print_registry[] */
29
30 #define KEY_MONITORS            "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/MONITORS"
31 #define KEY_FORMS               "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS"
32 #define KEY_CONTROL_PRINTERS    "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS"
33 #define KEY_ENVIRONMENTS        "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS"
34 #define KEY_CONTROL_PRINT       "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT"
35 #define KEY_WINNT_PRINTERS      "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS"
36 #define KEY_WINNT_PRINT         "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT"
37 #define KEY_PORTS               "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PORTS"
38
39 /* callback table for various registry paths below the ones we service in this module */
40         
41 struct reg_dyn_tree {
42         /* full key path in normalized form */
43         const char *path;
44         
45         /* callbscks for fetch/store operations */
46         int ( *fetch_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys );
47         BOOL (*store_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys );
48         int  (*fetch_values)  ( const char *path, REGVAL_CTR *values );
49         BOOL (*store_values)  ( const char *path, REGVAL_CTR *values );
50 };
51
52 /*********************************************************************
53  *********************************************************************
54  ** Utility Functions
55  *********************************************************************
56  *********************************************************************/
57
58 /***********************************************************************
59  simple function to prune a pathname down to the basename of a file 
60  **********************************************************************/
61  
62 static char* dos_basename ( char *path )
63 {
64         char *p;
65         
66         if ( !(p = strrchr( path, '\\' )) )
67                 p = path;
68         else
69                 p++;
70                 
71         return p;
72 }
73
74 /*********************************************************************
75  *********************************************************************
76  ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS"
77  *********************************************************************
78  *********************************************************************/
79
80 static int key_forms_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
81 {
82         char *p = reg_remaining_path( key + strlen(KEY_FORMS) );
83         
84         /* no keys below Forms */
85         
86         if ( p )
87                 return -1;
88                 
89         return 0;
90 }
91
92 /**********************************************************************
93  *********************************************************************/
94
95 static int key_forms_fetch_values( const char *key, REGVAL_CTR *values )
96 {
97         uint32          data[8];
98         int             i, num_values, form_index = 1;
99         nt_forms_struct *forms_list = NULL;
100         nt_forms_struct *form;
101                 
102         DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
103         
104         num_values = get_ntforms( &forms_list );
105                 
106         DEBUG(10,("hive_forms_fetch_values: [%d] user defined forms returned\n",
107                 num_values));
108
109         /* handle user defined forms */
110                                 
111         for ( i=0; i<num_values; i++ ) {
112                 form = &forms_list[i];
113                         
114                 data[0] = form->width;
115                 data[1] = form->length;
116                 data[2] = form->left;
117                 data[3] = form->top;
118                 data[4] = form->right;
119                 data[5] = form->bottom;
120                 data[6] = form_index++;
121                 data[7] = form->flag;
122                         
123                 regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) );       
124         }
125                 
126         SAFE_FREE( forms_list );
127         forms_list = NULL;
128                 
129         /* handle built-on forms */
130                 
131         num_values = get_builtin_ntforms( &forms_list );
132                 
133         DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
134                 num_values));
135                         
136         for ( i=0; i<num_values; i++ ) {
137                 form = &forms_list[i];
138                         
139                 data[0] = form->width;
140                 data[1] = form->length;
141                 data[2] = form->left;
142                 data[3] = form->top;
143                 data[4] = form->right;
144                 data[5] = form->bottom;
145                 data[6] = form_index++;
146                 data[7] = form->flag;
147                                         
148                 regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) );
149         }
150                 
151         SAFE_FREE( forms_list );
152         
153         return regval_ctr_numvals( values );
154 }
155
156 /*********************************************************************
157  *********************************************************************
158  ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS"
159  ** "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS"
160  *********************************************************************
161  *********************************************************************/
162
163 /*********************************************************************
164  strip off prefix for printers key.  DOes return a pointer to static 
165  memory.
166  *********************************************************************/
167
168 static char* strip_printers_prefix( const char *key )
169 {
170         char *subkeypath;
171         pstring path;
172         
173         pstrcpy( path, key );
174         normalize_reg_path( path );
175
176         /* normalizing the path does not change length, just key delimiters and case */
177
178         if ( strncmp( path, KEY_WINNT_PRINTERS, strlen(KEY_WINNT_PRINTERS) ) == 0 )
179                 subkeypath = reg_remaining_path( key + strlen(KEY_WINNT_PRINTERS) );
180         else
181                 subkeypath = reg_remaining_path( key + strlen(KEY_CONTROL_PRINTERS) );
182                 
183         return subkeypath;
184 }
185
186 /*********************************************************************
187  *********************************************************************/
188  
189 static int key_printers_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
190 {
191         int n_services = lp_numservices();      
192         int snum;
193         fstring sname;
194         int i;
195         int num_subkeys = 0;
196         char *printers_key;
197         char *printername, *printerdatakey;
198         NT_PRINTER_INFO_LEVEL *printer = NULL;
199         fstring *subkey_names = NULL;
200         
201         DEBUG(10,("key_printers_fetch_keys: key=>[%s]\n", key ? key : "NULL" ));
202         
203         printers_key = strip_printers_prefix( key );    
204         
205         if ( !printers_key ) {
206                 /* enumerate all printers */
207                 
208                 for (snum=0; snum<n_services; snum++) {
209                         if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
210                                 continue;
211
212                         /* don't report the [printers] share */
213
214                         if ( strequal( lp_servicename(snum), PRINTERS_NAME ) )
215                                 continue;
216                                 
217                         fstrcpy( sname, lp_servicename(snum) );
218                                 
219                         regsubkey_ctr_addkey( subkeys, sname );
220                 }
221                 
222                 num_subkeys = regsubkey_ctr_numkeys( subkeys );
223                 goto done;
224         }
225
226         /* get information for a specific printer */
227         
228         reg_split_path( printers_key, &printername, &printerdatakey );
229
230         /* validate the printer name */
231
232         for (snum=0; snum<n_services; snum++) {
233                 if ( !lp_snum_ok(snum) || !lp_print_ok(snum) )
234                         continue;
235                 if (strequal( lp_servicename(snum), printername ) )
236                         break;
237         }
238
239         if ( snum>=n_services
240                 || !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) ) 
241         {
242                 return -1;
243         }
244
245         num_subkeys = get_printer_subkeys( printer->info_2->data, printerdatakey?printerdatakey:"", &subkey_names );
246         
247         for ( i=0; i<num_subkeys; i++ )
248                 regsubkey_ctr_addkey( subkeys, subkey_names[i] );
249         
250         free_a_printer( &printer, 2 );
251                         
252         /* no other subkeys below here */
253
254 done:   
255         SAFE_FREE( subkey_names );
256         
257         return num_subkeys;
258 }
259
260 /**********************************************************************
261  Take a list of names and call add_printer_hook() if necessary
262  Note that we do this a little differently from Windows since the 
263  keyname is the sharename and not the printer name.
264  *********************************************************************/
265
266 static BOOL add_printers_by_registry( REGSUBKEY_CTR *subkeys )
267 {
268         int i, num_keys, snum;
269         char *printername;
270         NT_PRINTER_INFO_LEVEL_2 info2;
271         NT_PRINTER_INFO_LEVEL printer;
272         
273         ZERO_STRUCT( info2 );
274         printer.info_2 = &info2;
275         
276         num_keys = regsubkey_ctr_numkeys( subkeys );
277         
278         become_root();
279         for ( i=0; i<num_keys; i++ ) {
280                 printername = regsubkey_ctr_specific_key( subkeys, i );
281                 snum = find_service( printername );
282                 
283                 /* just verify a valied snum for now */
284                 if ( snum == -1 ) {
285                         fstrcpy( info2.printername, printername );
286                         fstrcpy( info2.sharename, printername );
287                         if ( !add_printer_hook( NULL, &printer ) ) {
288                                 DEBUG(0,("add_printers_by_registry: Failed to add printer [%s]\n",
289                                         printername));
290                         }       
291                 }
292         }
293         unbecome_root();
294
295         return True;
296 }
297
298 /**********************************************************************
299  *********************************************************************/
300
301 static BOOL key_printers_store_keys( const char *key, REGSUBKEY_CTR *subkeys )
302 {
303         char *printers_key;
304         char *printername, *printerdatakey;
305         NT_PRINTER_INFO_LEVEL *printer = NULL;
306         int i, num_subkeys, num_existing_keys;
307         char *subkeyname;
308         fstring *existing_subkeys = NULL;
309         
310         printers_key = strip_printers_prefix( key );
311         
312         if ( !printers_key ) {
313                 /* have to deal with some new or deleted printer */
314                 return add_printers_by_registry( subkeys );
315         }
316         
317         reg_split_path( printers_key, &printername, &printerdatakey );
318         
319         /* lookup the printer */
320         
321         if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, printername)) ) {
322                 DEBUG(0,("key_printers_store_keys: Tried to store subkey for bad printername %s\n", 
323                         printername));
324                 return False;
325         }
326         
327         /* get the top level printer keys */
328         
329         num_existing_keys = get_printer_subkeys( printer->info_2->data, "", &existing_subkeys );
330         
331         for ( i=0; i<num_existing_keys; i++ ) {
332         
333                 /* remove the key if it has been deleted */
334                 
335                 if ( !regsubkey_ctr_key_exists( subkeys, existing_subkeys[i] ) ) {
336                         DEBUG(5,("key_printers_store_keys: deleting key %s\n", 
337                                 existing_subkeys[i]));
338                         delete_printer_key( printer->info_2->data, existing_subkeys[i] );
339                 }
340         }
341
342         num_subkeys = regsubkey_ctr_numkeys( subkeys );
343         for ( i=0; i<num_subkeys; i++ ) {
344                 subkeyname = regsubkey_ctr_specific_key(subkeys, i);
345                 /* add any missing printer keys */
346                 if ( lookup_printerkey(printer->info_2->data, subkeyname) == -1 ) {
347                         DEBUG(5,("key_printers_store_keys: adding key %s\n", 
348                                 existing_subkeys[i]));
349                         if ( add_new_printer_key( printer->info_2->data, subkeyname ) == -1 ) 
350                                 return False;
351                 }
352         }
353         
354         /* write back to disk */
355         
356         mod_a_printer( printer, 2 );
357         
358         /* cleanup */
359         
360         if ( printer )
361                 free_a_printer( &printer, 2 );
362
363         return True;
364 }
365
366 /**********************************************************************
367  *********************************************************************/
368
369 static void fill_in_printer_values( NT_PRINTER_INFO_LEVEL_2 *info2, REGVAL_CTR *values )
370 {
371         DEVICEMODE      *devmode;
372         prs_struct      prs;
373         uint32          offset;
374         UNISTR2         data;
375         char            *p;
376         uint32 printer_status = PRINTER_STATUS_OK;
377         int snum;
378         
379         regval_ctr_addvalue( values, "Attributes",       REG_DWORD, (char*)&info2->attributes,       sizeof(info2->attributes) );
380         regval_ctr_addvalue( values, "Priority",         REG_DWORD, (char*)&info2->priority,         sizeof(info2->attributes) );
381         regval_ctr_addvalue( values, "ChangeID",         REG_DWORD, (char*)&info2->changeid,         sizeof(info2->changeid) );
382         regval_ctr_addvalue( values, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
383         
384         /* lie and say everything is ok since we don't want to call print_queue_length() to get the real status */
385         regval_ctr_addvalue( values, "Status",           REG_DWORD, (char*)&printer_status,          sizeof(info2->status) );
386
387         regval_ctr_addvalue( values, "StartTime",        REG_DWORD, (char*)&info2->starttime,        sizeof(info2->starttime) );
388         regval_ctr_addvalue( values, "UntilTime",        REG_DWORD, (char*)&info2->untiltime,        sizeof(info2->untiltime) );
389
390         /* strip the \\server\ from this string */
391         if ( !(p = strrchr( info2->printername, '\\' ) ) )
392                 p = info2->printername;
393         else
394                 p++;
395         init_unistr2( &data, p, UNI_STR_TERMINATE);
396         regval_ctr_addvalue( values, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
397
398         init_unistr2( &data, info2->location, UNI_STR_TERMINATE);
399         regval_ctr_addvalue( values, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
400
401         init_unistr2( &data, info2->comment, UNI_STR_TERMINATE);
402         regval_ctr_addvalue( values, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
403
404         init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE);
405         regval_ctr_addvalue( values, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
406
407         init_unistr2( &data, info2->portname, UNI_STR_TERMINATE);
408         regval_ctr_addvalue( values, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
409
410         init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE);
411         regval_ctr_addvalue( values, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
412
413         init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE);
414         regval_ctr_addvalue( values, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
415
416         init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE);
417         regval_ctr_addvalue( values, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
418
419         init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE);
420         regval_ctr_addvalue( values, "Print Processor",  REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
421
422         init_unistr2( &data, "RAW", UNI_STR_TERMINATE);
423         regval_ctr_addvalue( values, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
424
425                 
426         /* use a prs_struct for converting the devmode and security 
427            descriptor to REG_BINARY */
428         
429         prs_init( &prs, RPC_MAX_PDU_FRAG_LEN, values, MARSHALL);
430
431         /* stream the device mode */
432                 
433         snum = lp_servicenumber(info2->sharename);
434         if ( (devmode = construct_dev_mode( snum )) != NULL ) {                 
435                 if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
436                         offset = prs_offset( &prs );
437                         regval_ctr_addvalue( values, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
438                 }
439         }
440                 
441         prs_mem_clear( &prs );
442         prs_set_offset( &prs, 0 );
443                 
444         /* stream the printer security descriptor */
445         
446         if ( info2->secdesc_buf && info2->secdesc_buf->len )  {
447                 if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) {
448                         offset = prs_offset( &prs );
449                         regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&prs), offset );
450                 }
451         }
452
453         prs_mem_free( &prs );
454
455         return;         
456 }
457
458 /**********************************************************************
459  *********************************************************************/
460
461 static int key_printers_fetch_values( const char *key, REGVAL_CTR *values )
462 {
463         int             num_values;
464         char            *printers_key;
465         char            *printername, *printerdatakey;
466         NT_PRINTER_INFO_LEVEL   *printer = NULL;
467         NT_PRINTER_DATA *p_data;
468         int             i, key_index;
469         
470         printers_key = strip_printers_prefix( key );    
471         
472         /* top level key values stored in the registry has no values */
473         
474         if ( !printers_key ) {
475                 /* normalize to the 'HKLM\SOFTWARE\...\Print\Printers' ket */
476                 return regdb_fetch_values( KEY_WINNT_PRINTERS, values );
477         }
478         
479         /* lookup the printer object */
480         
481         reg_split_path( printers_key, &printername, &printerdatakey );
482         if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
483                 goto done;
484                 
485         if ( !printerdatakey ) {
486                 fill_in_printer_values( printer->info_2, values );
487                 goto done;
488         }
489                 
490         /* iterate over all printer data keys and fill the regval container */
491         
492         p_data = printer->info_2->data;
493         if ( (key_index = lookup_printerkey( p_data, printerdatakey )) == -1  ) {
494                 /* failure....should never happen if the client has a valid open handle first */
495                 DEBUG(10,("key_printers_fetch_values: Unknown keyname [%s]\n", printerdatakey));
496                 if ( printer )
497                         free_a_printer( &printer, 2 );
498                 return -1;
499         }
500         
501         num_values = regval_ctr_numvals( p_data->keys[key_index].values );      
502         for ( i=0; i<num_values; i++ )
503                 regval_ctr_copyvalue( values, regval_ctr_specific_value(p_data->keys[key_index].values, i) );
504                         
505
506 done:
507         if ( printer )
508                 free_a_printer( &printer, 2 );
509                 
510         return regval_ctr_numvals( values );
511 }
512
513 /**********************************************************************
514  *********************************************************************/
515
516 #define REG_IDX_ATTRIBUTES              1
517 #define REG_IDX_PRIORITY                2
518 #define REG_IDX_DEFAULT_PRIORITY        3
519 #define REG_IDX_CHANGEID                4
520 #define REG_IDX_STATUS                  5
521 #define REG_IDX_STARTTIME               6
522 #define REG_IDX_NAME                    7
523 #define REG_IDX_LOCATION                8
524 #define REG_IDX_DESCRIPTION             9
525 #define REG_IDX_PARAMETERS              10
526 #define REG_IDX_PORT                    12
527 #define REG_IDX_SHARENAME               13
528 #define REG_IDX_DRIVER                  14
529 #define REG_IDX_SEP_FILE                15
530 #define REG_IDX_PRINTPROC               16
531 #define REG_IDX_DATATYPE                17
532 #define REG_IDX_DEVMODE                 18
533 #define REG_IDX_SECDESC                 19
534 #define REG_IDX_UNTILTIME               20
535
536 struct {
537         const char *name;
538         int index;      
539 } printer_values_map[] = {
540         { "Attributes",         REG_IDX_ATTRIBUTES },
541         { "Priority",           REG_IDX_PRIORITY },
542         { "Default Priority",   REG_IDX_DEFAULT_PRIORITY },
543         { "ChangeID",           REG_IDX_CHANGEID },
544         { "Status",             REG_IDX_STATUS },
545         { "StartTime",          REG_IDX_STARTTIME },
546         { "UntilTime",          REG_IDX_UNTILTIME },
547         { "Name",               REG_IDX_NAME },
548         { "Location",           REG_IDX_LOCATION },
549         { "Descrioption",       REG_IDX_DESCRIPTION },
550         { "Parameters",         REG_IDX_PARAMETERS },
551         { "Port",               REG_IDX_PORT },
552         { "Share Name",         REG_IDX_SHARENAME },
553         { "Printer Driver",     REG_IDX_DRIVER },
554         { "Separator File",     REG_IDX_SEP_FILE },
555         { "Print Processor",    REG_IDX_PRINTPROC },
556         { "Datatype",           REG_IDX_DATATYPE },
557         { "Default Devmode",    REG_IDX_DEVMODE },
558         { "Security",           REG_IDX_SECDESC },
559         { NULL, -1 }
560 };
561
562
563 static int find_valuename_index( const char *valuename )
564 {
565         int i;
566         
567         for ( i=0; printer_values_map[i].name; i++ ) {
568                 if ( strequal( valuename, printer_values_map[i].name ) )
569                         return printer_values_map[i].index;
570         }
571         
572         return -1;
573 }
574
575 /**********************************************************************
576  *********************************************************************/
577
578 static void convert_values_to_printer_info_2( NT_PRINTER_INFO_LEVEL_2 *printer2, REGVAL_CTR *values )
579 {
580         int num_values = regval_ctr_numvals( values );
581         uint32 value_index;
582         REGISTRY_VALUE *val;
583         int i;
584         
585         for ( i=0; i<num_values; i++ ) {
586                 val = regval_ctr_specific_value( values, i );
587                 value_index = find_valuename_index( regval_name( val ) );
588                 
589                 switch( value_index ) {
590                         case REG_IDX_ATTRIBUTES:
591                                 printer2->attributes = (uint32)(*regval_data_p(val));
592                                 break;
593                         case REG_IDX_PRIORITY:
594                                 printer2->priority = (uint32)(*regval_data_p(val));
595                                 break;
596                         case REG_IDX_DEFAULT_PRIORITY:
597                                 printer2->default_priority = (uint32)(*regval_data_p(val));
598                                 break;
599                         case REG_IDX_CHANGEID:
600                                 printer2->changeid = (uint32)(*regval_data_p(val));
601                                 break;
602                         case REG_IDX_STARTTIME:
603                                 printer2->starttime = (uint32)(*regval_data_p(val));
604                                 break;
605                         case REG_IDX_UNTILTIME:
606                                 printer2->untiltime = (uint32)(*regval_data_p(val));
607                                 break;
608                         case REG_IDX_NAME:
609                                 rpcstr_pull( printer2->printername, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
610                                 break;
611                         case REG_IDX_LOCATION:
612                                 rpcstr_pull( printer2->location, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
613                                 break;
614                         case REG_IDX_DESCRIPTION:
615                                 rpcstr_pull( printer2->comment, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
616                                 break;
617                         case REG_IDX_PARAMETERS:
618                                 rpcstr_pull( printer2->parameters, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
619                                 break;
620                         case REG_IDX_PORT:
621                                 rpcstr_pull( printer2->portname, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
622                                 break;
623                         case REG_IDX_SHARENAME:
624                                 rpcstr_pull( printer2->sharename, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
625                                 break;
626                         case REG_IDX_DRIVER:
627                                 rpcstr_pull( printer2->drivername, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
628                                 break;
629                         case REG_IDX_SEP_FILE:
630                                 rpcstr_pull( printer2->sepfile, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
631                                 break;
632                         case REG_IDX_PRINTPROC:
633                                 rpcstr_pull( printer2->printprocessor, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
634                                 break;
635                         case REG_IDX_DATATYPE:
636                                 rpcstr_pull( printer2->datatype, regval_data_p(val), sizeof(fstring), regval_size(val), 0 );
637                                 break;
638                         case REG_IDX_DEVMODE:
639                                 break;
640                         case REG_IDX_SECDESC:
641                                 break;          
642                         default:
643                                 /* unsupported value...throw away */
644                                 DEBUG(8,("convert_values_to_printer_info_2: Unsupported registry value [%s]\n", 
645                                         regval_name( val ) ));
646                 }
647         }
648         
649         return;
650 }       
651
652 /**********************************************************************
653  *********************************************************************/
654
655 static BOOL key_printers_store_values( const char *key, REGVAL_CTR *values )
656 {
657         char *printers_key;
658         char *printername, *keyname;
659         NT_PRINTER_INFO_LEVEL   *printer = NULL;
660         WERROR result;
661         
662         printers_key = strip_printers_prefix( key );
663         
664         /* values in the top level key get stored in the registry */
665
666         if ( !printers_key ) {
667                 /* normalize on the 'HKLM\SOFTWARE\....\Print\Printers' key */
668                 return regdb_store_values( KEY_WINNT_PRINTERS, values );
669         }
670         
671         reg_split_path( printers_key, &printername, &keyname );
672
673         if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, printername) ) )
674                 return False;
675
676         /* deal with setting values directly under the printername */
677
678         if ( !keyname ) {
679                 convert_values_to_printer_info_2( printer->info_2, values );
680         }
681         else {
682                 int num_values = regval_ctr_numvals( values );
683                 int i;
684                 REGISTRY_VALUE *val;
685                 
686                 delete_printer_key( printer->info_2->data, keyname );
687                 
688                 /* deal with any subkeys */
689                 for ( i=0; i<num_values; i++ ) {
690                         val = regval_ctr_specific_value( values, i );
691                         result = set_printer_dataex( printer, keyname, 
692                                 regval_name( val ),
693                                 regval_type( val ),
694                                 regval_data_p( val ),
695                                 regval_size( val ) );
696                         if ( !W_ERROR_IS_OK(result) ) {
697                                 DEBUG(0,("key_printers_store_values: failed to set printer data [%s]!\n",
698                                         keyname));
699                                 free_a_printer( &printer, 2 );
700                                 return False;
701                         }
702                 }
703         }
704
705         result = mod_a_printer( printer, 2 );
706
707         free_a_printer( &printer, 2 );
708
709         return W_ERROR_IS_OK(result);
710 }
711
712 /*********************************************************************
713  *********************************************************************
714  ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS"
715  *********************************************************************
716  *********************************************************************/
717
718 static int key_driver_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
719 {
720         const char *environments[] = {
721                 "Windows 4.0",
722                 "Windows NT x86",
723                 "Windows NT R4000",
724                 "Windows NT Alpha_AXP",
725                 "Windows NT PowerPC",
726                 "Windows IA64",
727                 "Windows x64",
728                 NULL };
729         fstring *drivers = NULL;
730         int i, env_index, num_drivers;
731         char *keystr, *base, *subkeypath;
732         pstring key2;
733         int num_subkeys = -1;
734         int version;
735
736         DEBUG(10,("key_driver_fetch_keys key=>[%s]\n", key ? key : "NULL" ));
737         
738         keystr = reg_remaining_path( key + strlen(KEY_ENVIRONMENTS) );  
739         
740         /* list all possible architectures */
741         
742         if ( !keystr ) {
743                 for ( num_subkeys=0; environments[num_subkeys]; num_subkeys++ ) 
744                         regsubkey_ctr_addkey( subkeys,  environments[num_subkeys] );
745
746                 return num_subkeys;
747         }
748         
749         /* we are dealing with a subkey of "Environments */
750         
751         pstrcpy( key2, keystr );
752         keystr = key2;
753         reg_split_path( keystr, &base, &subkeypath );
754         
755         /* sanity check */
756         
757         for ( env_index=0; environments[env_index]; env_index++ ) {
758                 if ( strequal( environments[env_index], base ) )
759                         break;
760         }
761         if ( !environments[env_index] )
762                 return -1;
763         
764         /* ...\Print\Environements\...\ */
765         
766         if ( !subkeypath ) {
767                 regsubkey_ctr_addkey( subkeys, "Drivers" );
768                 regsubkey_ctr_addkey( subkeys, "Print Processors" );
769                                 
770                 return 2;
771         }
772         
773         /* more of the key path to process */
774         
775         keystr = subkeypath;
776         reg_split_path( keystr, &base, &subkeypath );   
777                 
778         /* ...\Print\Environements\...\Drivers\ */
779         
780         if ( !subkeypath ) {
781                 if ( strequal(base, "Drivers") ) {
782                         switch ( env_index ) {
783                                 case 0: /* Win9x */
784                                         regsubkey_ctr_addkey( subkeys, "Version-0" );
785                                         break;
786                                 default: /* Windows NT based systems */
787                                         regsubkey_ctr_addkey( subkeys, "Version-2" );
788                                         regsubkey_ctr_addkey( subkeys, "Version-3" );
789                                         break;                  
790                         }
791                 
792                         return regsubkey_ctr_numkeys( subkeys );
793                 } else if ( strequal(base, "Print Processors") ) {
794                         if ( env_index == 1 || env_index == 5 || env_index == 6 )
795                                 regsubkey_ctr_addkey( subkeys, "winprint" );
796                                 
797                         return regsubkey_ctr_numkeys( subkeys );
798                 } else
799                         return -1;      /* bad path */
800         }
801         
802         /* we finally get to enumerate the drivers */
803         
804         /* only one possible subkey below PrintProc key */
805
806         if ( strequal(base, "Print Processors") ) {
807                 keystr = subkeypath;
808                 reg_split_path( keystr, &base, &subkeypath );
809
810                 /* no subkeys below this point */
811
812                 if ( subkeypath )
813                         return -1;
814
815                 /* only allow one keyname here -- 'winprint' */
816
817                 return strequal( base, "winprint" ) ? 0 : -1;
818         }
819         
820         /* only dealing with drivers from here on out */
821
822         keystr = subkeypath;
823         reg_split_path( keystr, &base, &subkeypath );
824         version = atoi(&base[strlen(base)-1]);
825                         
826         switch (env_index) {
827         case 0:
828                 if ( version != 0 )
829                         return -1;
830                 break;
831         default:
832                 if ( version != 2 && version != 3 )
833                         return -1;
834                 break;
835         }
836
837         
838         if ( !subkeypath ) {
839                 num_drivers = get_ntdrivers( &drivers, environments[env_index], version );
840                 for ( i=0; i<num_drivers; i++ )
841                         regsubkey_ctr_addkey( subkeys, drivers[i] );
842                         
843                 return regsubkey_ctr_numkeys( subkeys );        
844         }       
845         
846         /* if anything else left, just say if has no subkeys */
847         
848         DEBUG(1,("key_driver_fetch_keys unhandled key [%s] (subkey == %s\n", 
849                 key, subkeypath ));
850         
851         return 0;
852 }
853
854
855 /**********************************************************************
856  *********************************************************************/
857
858 static void fill_in_driver_values( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3, REGVAL_CTR *values )
859 {
860         char *buffer = NULL;
861         int buffer_size = 0;
862         int i, length;
863         char *filename;
864         UNISTR2 data;
865         
866         filename = dos_basename( info3->driverpath );
867         init_unistr2( &data, filename, UNI_STR_TERMINATE);
868         regval_ctr_addvalue( values, "Driver", REG_SZ, (char*)data.buffer, 
869                 data.uni_str_len*sizeof(uint16) );
870         
871         filename = dos_basename( info3->configfile );
872         init_unistr2( &data, filename, UNI_STR_TERMINATE);
873         regval_ctr_addvalue( values, "Configuration File", REG_SZ, (char*)data.buffer, 
874                 data.uni_str_len*sizeof(uint16) );
875         
876         filename = dos_basename( info3->datafile );
877         init_unistr2( &data, filename, UNI_STR_TERMINATE);
878         regval_ctr_addvalue( values, "Data File", REG_SZ, (char*)data.buffer, 
879                 data.uni_str_len*sizeof(uint16) );
880         
881         filename = dos_basename( info3->helpfile );
882         init_unistr2( &data, filename, UNI_STR_TERMINATE);
883         regval_ctr_addvalue( values, "Help File", REG_SZ, (char*)data.buffer, 
884                 data.uni_str_len*sizeof(uint16) );
885         
886         init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE);
887         regval_ctr_addvalue( values, "Data Type", REG_SZ, (char*)data.buffer, 
888                 data.uni_str_len*sizeof(uint16) );
889         
890         regval_ctr_addvalue( values, "Version", REG_DWORD, (char*)&info3->cversion, 
891                 sizeof(info3->cversion) );
892         
893         if ( info3->dependentfiles ) {
894                 /* place the list of dependent files in a single 
895                    character buffer, separating each file name by
896                    a NULL */
897                    
898                 for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ ) {
899                         /* strip the path to only the file's base name */
900                 
901                         filename = dos_basename( info3->dependentfiles[i] );
902                         
903                         length = strlen(filename);
904                 
905                         buffer = SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) );
906                         if ( !buffer ) {
907                                 break;
908                         }
909                         
910                         init_unistr2( &data, filename, UNI_STR_TERMINATE);
911                         memcpy( buffer+buffer_size, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
912                 
913                         buffer_size += (length + 1)*sizeof(uint16);
914                 }
915                 
916                 /* terminated by double NULL.  Add the final one here */
917                 
918                 buffer = SMB_REALLOC( buffer, buffer_size + 2 );
919                 if ( !buffer ) {
920                         buffer_size = 0;
921                 } else {
922                         buffer[buffer_size++] = '\0';
923                         buffer[buffer_size++] = '\0';
924                 }
925         }
926         
927         regval_ctr_addvalue( values, "Dependent Files",    REG_MULTI_SZ, buffer, buffer_size );
928                 
929         SAFE_FREE( buffer );
930         
931         return;
932 }
933
934 /**********************************************************************
935  *********************************************************************/
936
937 static int driver_arch_fetch_values( char *key, REGVAL_CTR *values )
938 {
939         char            *keystr, *base, *subkeypath;
940         fstring         arch_environment;
941         fstring         driver;
942         int             version;
943         NT_PRINTER_DRIVER_INFO_LEVEL    driver_ctr;
944         WERROR          w_result;
945
946         reg_split_path( key, &base, &subkeypath );
947         
948         /* no values in 'Environments\Drivers\Windows NT x86' */
949         
950         if ( !subkeypath ) 
951                 return 0;
952                 
953         /* We have the Architecture string and some subkey name:
954            Currently we only support
955            * Drivers
956            * Print Processors
957            Anything else is an error.
958            */
959
960         fstrcpy( arch_environment, base );
961         
962         keystr = subkeypath;
963         reg_split_path( keystr, &base, &subkeypath );
964
965         if ( strequal(base, "Print Processors") )
966                 return 0;
967
968         /* only Drivers key can be left */
969                 
970         if ( !strequal(base, "Drivers") )
971                 return -1;
972                         
973         if ( !subkeypath )
974                 return 0;
975         
976         /* We know that we have Architechure\Drivers with some subkey name
977            The subkey name has to be Version-XX */
978         
979         keystr = subkeypath;
980         reg_split_path( keystr, &base, &subkeypath );
981
982         if ( !subkeypath )
983                 return 0;
984                 
985         version = atoi(&base[strlen(base)-1]);
986
987         /* BEGIN PRINTER DRIVER NAME BLOCK */
988         
989         keystr = subkeypath;
990         reg_split_path( keystr, &base, &subkeypath );
991         
992         /* don't go any deeper for now */
993         
994         fstrcpy( driver, base );
995         
996         w_result = get_a_printer_driver( &driver_ctr, 3, driver, arch_environment, version );
997
998         if ( !W_ERROR_IS_OK(w_result) )
999                 return -1;
1000                 
1001         fill_in_driver_values( driver_ctr.info_3, values ); 
1002         
1003         free_a_printer_driver( driver_ctr, 3 );
1004
1005         /* END PRINTER DRIVER NAME BLOCK */
1006
1007                                                 
1008         DEBUG(8,("key_driver_fetch_values: Exit\n"));
1009         
1010         return regval_ctr_numvals( values );
1011 }
1012
1013 /**********************************************************************
1014  *********************************************************************/
1015
1016 static int key_driver_fetch_values( const char *key, REGVAL_CTR *values )
1017 {
1018         char *keystr;
1019         pstring subkey;
1020         
1021         DEBUG(8,("key_driver_fetch_values: Enter key => [%s]\n", key ? key : "NULL"));
1022
1023         /* no values in the Environments key */
1024         
1025         if ( !(keystr = reg_remaining_path( key + strlen(KEY_ENVIRONMENTS) )) )
1026                 return 0;
1027         
1028         pstrcpy( subkey, keystr);
1029         
1030         /* pass off to handle subkeys */
1031         
1032         return driver_arch_fetch_values( subkey, values );
1033 }
1034
1035 /*********************************************************************
1036  *********************************************************************
1037  ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT"
1038  *********************************************************************
1039  *********************************************************************/
1040
1041 static int key_print_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys )
1042 {       
1043         int key_len = strlen(key);
1044         
1045         /* no keys below 'Print' handled here */
1046         
1047         if ( (key_len != strlen(KEY_CONTROL_PRINT)) && (key_len != strlen(KEY_WINNT_PRINT)) )
1048                 return -1;
1049
1050         regsubkey_ctr_addkey( subkeys, "Environments" );
1051         regsubkey_ctr_addkey( subkeys, "Monitors" );
1052         regsubkey_ctr_addkey( subkeys, "Forms" );
1053         regsubkey_ctr_addkey( subkeys, "Printers" );
1054         
1055         return regsubkey_ctr_numkeys( subkeys );
1056 }
1057
1058 /**********************************************************************
1059  *********************************************************************
1060  ** Structure to hold dispatch table of ops for various printer keys.
1061  ** Make sure to always store deeper keys along the same path first so 
1062  ** we ge a more specific match.
1063  *********************************************************************
1064  *********************************************************************/
1065
1066 static struct reg_dyn_tree print_registry[] = {
1067 /* just pass the monitor onto the registry tdb */
1068 { KEY_MONITORS,
1069         &regdb_fetch_keys, 
1070         &regdb_store_keys,
1071         &regdb_fetch_values,
1072         &regdb_store_values },
1073 { KEY_FORMS, 
1074         &key_forms_fetch_keys, 
1075         NULL, 
1076         &key_forms_fetch_values,
1077         NULL },
1078 { KEY_CONTROL_PRINTERS, 
1079         &key_printers_fetch_keys,
1080         &key_printers_store_keys,
1081         &key_printers_fetch_values,
1082         &key_printers_store_values },
1083 { KEY_ENVIRONMENTS,
1084         &key_driver_fetch_keys,
1085         NULL,
1086         &key_driver_fetch_values,
1087         NULL },
1088 { KEY_CONTROL_PRINT,
1089         &key_print_fetch_keys,
1090         NULL,
1091         NULL,
1092         NULL },
1093 { KEY_WINNT_PRINTERS,
1094         &key_printers_fetch_keys,
1095         &key_printers_store_keys,
1096         &key_printers_fetch_values,
1097         &key_printers_store_values },
1098 { KEY_PORTS,
1099         &regdb_fetch_keys, 
1100         &regdb_store_keys,
1101         &regdb_fetch_values,
1102         &regdb_store_values },
1103         
1104 { NULL, NULL, NULL, NULL, NULL }
1105 };
1106
1107
1108 /**********************************************************************
1109  *********************************************************************
1110  ** Main reg_printing interface functions
1111  *********************************************************************
1112  *********************************************************************/
1113
1114 /***********************************************************************
1115  Lookup a key in the print_registry table, returning its index.
1116  -1 on failure
1117  **********************************************************************/
1118
1119 static int match_registry_path( const char *key )
1120 {
1121         int i;
1122         pstring path;
1123         
1124         if ( !key )
1125                 return -1;
1126
1127         pstrcpy( path, key );
1128         normalize_reg_path( path );
1129         
1130         for ( i=0; print_registry[i].path; i++ ) {
1131                 if ( strncmp( path, print_registry[i].path, strlen(print_registry[i].path) ) == 0 )
1132                         return i;
1133         }
1134         
1135         return -1;
1136 }
1137
1138 /***********************************************************************
1139  **********************************************************************/
1140
1141 static int regprint_fetch_reg_keys( const char *key, REGSUBKEY_CTR *subkeys )
1142 {
1143         int i = match_registry_path( key );
1144         
1145         if ( i == -1 )
1146                 return -1;
1147                 
1148         if ( !print_registry[i].fetch_subkeys )
1149                 return -1;
1150                 
1151         return print_registry[i].fetch_subkeys( key, subkeys );
1152 }
1153
1154 /**********************************************************************
1155  *********************************************************************/
1156
1157 static BOOL regprint_store_reg_keys( const char *key, REGSUBKEY_CTR *subkeys )
1158 {
1159         int i = match_registry_path( key );
1160         
1161         if ( i == -1 )
1162                 return False;
1163         
1164         if ( !print_registry[i].store_subkeys )
1165                 return False;
1166                 
1167         return print_registry[i].store_subkeys( key, subkeys );
1168 }
1169
1170 /**********************************************************************
1171  *********************************************************************/
1172
1173 static int regprint_fetch_reg_values( const char *key, REGVAL_CTR *values )
1174 {
1175         int i = match_registry_path( key );
1176         
1177         if ( i == -1 )
1178                 return -1;
1179         
1180         /* return 0 values by default since we know the key had 
1181            to exist because the client opened a handle */
1182            
1183         if ( !print_registry[i].fetch_values )
1184                 return 0;
1185                 
1186         return print_registry[i].fetch_values( key, values );
1187 }
1188
1189 /**********************************************************************
1190  *********************************************************************/
1191
1192 static BOOL regprint_store_reg_values( const char *key, REGVAL_CTR *values )
1193 {
1194         int i = match_registry_path( key );
1195         
1196         if ( i == -1 )
1197                 return False;
1198         
1199         if ( !print_registry[i].store_values )
1200                 return False;
1201                 
1202         return print_registry[i].store_values( key, values );
1203 }
1204
1205 /* 
1206  * Table of function pointers for accessing printing data
1207  */
1208  
1209 REGISTRY_OPS printing_ops = {
1210         regprint_fetch_reg_keys,
1211         regprint_fetch_reg_values,
1212         regprint_store_reg_keys,
1213         regprint_store_reg_values,
1214         NULL
1215 };
1216
1217