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