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