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