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