r7995: * privileges are local except when they're *not*
[sfrench/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 #define MAX_TOP_LEVEL_KEYS      3
29
30 /* some symbolic indexes into the top_level_keys */
31
32 #define KEY_INDEX_ENVIR         0
33 #define KEY_INDEX_FORMS         1
34 #define KEY_INDEX_PRINTER       2
35
36 static const char *top_level_keys[MAX_TOP_LEVEL_KEYS] = { 
37         "Environments", 
38         "Forms",
39         "Printers" 
40 };
41
42 /**********************************************************************
43  It is safe to assume that every registry path passed into on of 
44  the exported functions here begins with KEY_PRINTING else
45  these functions would have never been called.  This is a small utility
46  function to strip the beginning of the path and make a copy that the 
47  caller can modify.  Note that the caller is responsible for releasing
48  the memory allocated here.
49  **********************************************************************/
50
51 static char* trim_reg_path( const char *path )
52 {
53         const char *p;
54         uint16 key_len = strlen(path);
55         uint16 base_key_len;
56
57         int key_printing_len = strlen( KEY_PRINTING );
58         int key_printing2k_len = strlen( KEY_PRINTING_2K );
59         int key_printing_ports_len = strlen( KEY_PRINTING_PORTS );
60
61
62         
63         /* 
64          * sanity check...this really should never be True.
65          * It is only here to prevent us from accessing outside
66          * the path buffer in the extreme case.
67          */
68         
69         if ( (key_len < key_printing_len) 
70                 && (key_len < key_printing2k_len) 
71                 && (key_len < key_printing_ports_len) )
72         {
73                 DEBUG(0,("trim_reg_path: Registry path too short! [%s]\n", path));
74                 return NULL;
75         }
76
77         base_key_len = 0;
78         if ( StrnCaseCmp( KEY_PRINTING, path, key_printing_len ) == 0 ) {
79                 base_key_len = key_printing_len;
80         }
81         else if ( StrnCaseCmp( KEY_PRINTING_2K, path, key_printing2k_len ) == 0 ) {
82                 base_key_len = key_printing2k_len;
83         }
84         else if ( StrnCaseCmp( KEY_PRINTING_PORTS, path, key_printing2k_len ) == 0 ) {
85                 base_key_len = key_printing_ports_len;
86         }
87         else {
88                 DEBUG(0,("trim_reg_path: invalid path [%s]\n", path ));
89                 return NULL;
90         }
91         
92         p = path + base_key_len;
93         
94         if ( *p == '\\' )
95                 p++;
96         
97         if ( *p )
98                 return SMB_STRDUP(p);
99         else
100                 return NULL;
101 }
102
103 /**********************************************************************
104  *********************************************************************/
105  
106 static int fill_ports_values( REGVAL_CTR *values )
107 {
108         int numlines, i;
109         char **lines;
110         UNISTR2 data;
111         WERROR result;
112
113         result = enumports_hook( &numlines, &lines );
114
115         if ( !W_ERROR_IS_OK(result) )
116                 return -1;
117
118         init_unistr2( &data, "", UNI_STR_TERMINATE);
119         for ( i=0; i<numlines; i++ )
120                 regval_ctr_addvalue( values, lines[i], REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
121
122         return numlines;
123 }
124  
125
126 /**********************************************************************
127  handle enumeration of subkeys below KEY_PRINTING\Environments
128  Environments\$ARCH\Print Processors
129  Environments\$ARCH\Drivers\{0,2,3}
130  *********************************************************************/
131  
132 #define ENVIRONMENT_DRIVERS     1
133 #define ENVIRONMENT_PRINTPROC   2
134
135 static int print_subpath_environments( char *key, REGSUBKEY_CTR *subkeys )
136 {
137         const char *environments[] = {
138                 "Windows 4.0",
139                 "Windows NT x86",
140                 "Windows NT R4000",
141                 "Windows NT Alpha_AXP",
142                 "Windows NT PowerPC",
143                 "Windows IA64",
144                 "Windows x64",
145                 NULL };
146         fstring *drivers = NULL;
147         int i, env_index, num_drivers;
148         char *keystr, *base, *subkeypath;
149         pstring key2;
150         int num_subkeys = -1;
151         int env_subkey_type = 0;
152         int version;
153
154         DEBUG(10,("print_subpath_environments: key=>[%s]\n", key ? key : "NULL" ));
155         
156         /* list all possible architectures */
157         
158         if ( !key ) {
159                 for ( num_subkeys=0; environments[num_subkeys]; num_subkeys++ ) 
160                         regsubkey_ctr_addkey( subkeys,  environments[num_subkeys] );
161
162                 return num_subkeys;
163         }
164         
165         /* we are dealing with a subkey of "Environments */
166         
167         pstrcpy( key2, key );
168         keystr = key2;
169         reg_split_path( keystr, &base, &subkeypath );
170         
171         /* sanity check */
172         
173         for ( env_index=0; environments[env_index]; env_index++ ) {
174                 if ( strequal( environments[env_index], base ) )
175                         break;
176         }
177         if ( !environments[env_index] )
178                 return -1;
179         
180         /* ...\Print\Environements\...\ */
181         
182         if ( !subkeypath ) {
183                 regsubkey_ctr_addkey( subkeys, "Drivers" );
184                 regsubkey_ctr_addkey( subkeys, "Print Processors" );
185                                 
186                 return 2;
187         }
188         
189         /* more of the key path to process */
190         
191         keystr = subkeypath;
192         reg_split_path( keystr, &base, &subkeypath );   
193                 
194         /* ...\Print\Environements\...\Drivers\ */
195         
196         if ( strequal(base, "Drivers") )
197                 env_subkey_type = ENVIRONMENT_DRIVERS;
198         else if ( strequal(base, "Print Processors") )
199                 env_subkey_type = ENVIRONMENT_PRINTPROC;
200         else
201                 /* invalid path */
202                 return -1;
203         
204         if ( !subkeypath ) {
205                 switch ( env_subkey_type ) {
206                 case ENVIRONMENT_DRIVERS:
207                         switch ( env_index ) {
208                                 case 0: /* Win9x */
209                                         regsubkey_ctr_addkey( subkeys, "Version-0" );
210                                         break;
211                                 default: /* Windows NT based systems */
212                                         regsubkey_ctr_addkey( subkeys, "Version-2" );
213                                         regsubkey_ctr_addkey( subkeys, "Version-3" );
214                                         break;                  
215                         }
216                 
217                         return regsubkey_ctr_numkeys( subkeys );
218                 
219                 case ENVIRONMENT_PRINTPROC:
220                         if ( env_index == 1 || env_index == 5 || env_index == 6 )
221                                 regsubkey_ctr_addkey( subkeys, "winprint" );
222                                 
223                         return regsubkey_ctr_numkeys( subkeys );
224                 }
225         }
226         
227         /* we finally get to enumerate the drivers */
228         
229         keystr = subkeypath;
230         reg_split_path( keystr, &base, &subkeypath );
231
232         /* get thr print processors key out of the way */
233         if ( env_subkey_type == ENVIRONMENT_PRINTPROC ) {
234                 if ( !strequal( base, "winprint" ) )
235                         return -1;
236                 return !subkeypath ? 0 : -1;
237         }
238         
239         /* only dealing with drivers from here on out */
240         
241         version = atoi(&base[strlen(base)-1]);
242                         
243         switch (env_index) {
244         case 0:
245                 if ( version != 0 )
246                         return -1;
247                 break;
248         default:
249                 if ( version != 2 && version != 3 )
250                         return -1;
251                 break;
252         }
253
254         
255         if ( !subkeypath ) {
256                 num_drivers = get_ntdrivers( &drivers, environments[env_index], version );
257                 for ( i=0; i<num_drivers; i++ )
258                         regsubkey_ctr_addkey( subkeys, drivers[i] );
259                         
260                 return regsubkey_ctr_numkeys( subkeys );        
261         }       
262         
263         /* if anything else left, just say if has no subkeys */
264         
265         DEBUG(1,("print_subpath_environments: unhandled key [%s] (subkey == %s\n", 
266                 key, subkeypath ));
267         
268         return 0;
269 }
270
271 /***********************************************************************
272  simple function to prune a pathname down to the basename of a file 
273  **********************************************************************/
274  
275 static char* dos_basename ( char *path )
276 {
277         char *p;
278         
279         p = strrchr( path, '\\' );
280         if ( p )
281                 p++;
282         else
283                 p = path;
284                 
285         return p;
286 }
287
288 /**********************************************************************
289  handle enumeration of values below 
290  KEY_PRINTING\Environments\<arch>\<version>\<drivername>
291  *********************************************************************/
292  
293 static int print_subpath_values_environments( char *key, REGVAL_CTR *val )
294 {
295         char            *keystr, *base, *subkeypath;
296         pstring         key2;
297         fstring         arch_environment;
298         fstring         driver;
299         int             version;
300         NT_PRINTER_DRIVER_INFO_LEVEL    driver_ctr;
301         NT_PRINTER_DRIVER_INFO_LEVEL_3  *info3;
302         WERROR          w_result;
303         char            *buffer = NULL;
304         char            *buffer2 = NULL;
305         int             buffer_size = 0;
306         int             i, length;
307         char            *filename;
308         UNISTR2         data;
309         int             env_subkey_type = 0;
310         
311         
312         DEBUG(8,("print_subpath_values_environments: Enter key => [%s]\n", key ? key : "NULL"));
313         
314         if ( !key )
315                 return 0;
316                 
317         /* The only keys below KEY_PRINTING\Environments is the 
318            specific printer driver info */
319         
320         /* environment */
321         
322         pstrcpy( key2, key );
323         keystr = key2;
324         reg_split_path( keystr, &base, &subkeypath );
325         if ( !subkeypath ) 
326                 return 0;
327         fstrcpy( arch_environment, base );
328         
329         /* Driver */
330         
331         keystr = subkeypath;
332         reg_split_path( keystr, &base, &subkeypath );
333
334         if ( strequal(base, "Drivers") )
335                 env_subkey_type = ENVIRONMENT_DRIVERS;
336         else if ( strequal(base, "Print Processors") )
337                 env_subkey_type = ENVIRONMENT_PRINTPROC;
338         else
339                 /* invalid path */
340                 return -1;
341         
342         if ( !subkeypath )
343                 return 0;
344
345         /* for now bail out if we are seeing anything other than the drivers key */
346         
347         if ( env_subkey_type == ENVIRONMENT_PRINTPROC )
348                 return 0;
349                 
350         keystr = subkeypath;
351         reg_split_path( keystr, &base, &subkeypath );
352                 
353         version = atoi(&base[strlen(base)-1]);
354
355         /* printer driver name */
356         
357         keystr = subkeypath;
358         reg_split_path( keystr, &base, &subkeypath );
359         /* don't go any deeper for now */
360         if ( subkeypath )
361                 return 0;
362         fstrcpy( driver, base );
363
364         w_result = get_a_printer_driver( &driver_ctr, 3, driver, arch_environment, version );
365
366         if ( !W_ERROR_IS_OK(w_result) )
367                 return -1;
368                 
369         /* build the values out of the driver information */
370         info3 = driver_ctr.info_3;
371         
372         filename = dos_basename( info3->driverpath );
373         init_unistr2( &data, filename, UNI_STR_TERMINATE);
374         regval_ctr_addvalue( val, "Driver",             REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
375         
376         filename = dos_basename( info3->configfile );
377         init_unistr2( &data, filename, UNI_STR_TERMINATE);
378         regval_ctr_addvalue( val, "Configuration File", REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
379         
380         filename = dos_basename( info3->datafile );
381         init_unistr2( &data, filename, UNI_STR_TERMINATE);
382         regval_ctr_addvalue( val, "Data File",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
383         
384         filename = dos_basename( info3->helpfile );
385         init_unistr2( &data, filename, UNI_STR_TERMINATE);
386         regval_ctr_addvalue( val, "Help File",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
387         
388         init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE);
389         regval_ctr_addvalue( val, "Data Type",          REG_SZ,       (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
390         
391         regval_ctr_addvalue( val, "Version",            REG_DWORD,    (char*)&info3->cversion, sizeof(info3->cversion) );
392         
393         if ( info3->dependentfiles ) {
394                 /* place the list of dependent files in a single 
395                    character buffer, separating each file name by
396                    a NULL */
397                    
398                 for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ ) {
399                         /* strip the path to only the file's base name */
400                 
401                         filename = dos_basename( info3->dependentfiles[i] );
402                         
403                         length = strlen(filename);
404                 
405                         buffer2 = SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) );
406                         if ( !buffer2 )
407                                 break;
408                         buffer = buffer2;
409                         
410                         init_unistr2( &data, filename, UNI_STR_TERMINATE);
411                         memcpy( buffer+buffer_size, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
412                 
413                         buffer_size += (length + 1)*sizeof(uint16);
414                 }
415                 
416                 /* terminated by double NULL.  Add the final one here */
417                 
418                 buffer2 = SMB_REALLOC( buffer, buffer_size + 2 );
419                 if ( !buffer2 ) {
420                         SAFE_FREE( buffer );
421                         buffer_size = 0;
422                 } else {
423                         buffer = buffer2;
424                         buffer[buffer_size++] = '\0';
425                         buffer[buffer_size++] = '\0';
426                 }
427         }
428         
429         regval_ctr_addvalue( val, "Dependent Files",    REG_MULTI_SZ, buffer, buffer_size );
430         
431         free_a_printer_driver( driver_ctr, 3 );
432         
433         SAFE_FREE( buffer );
434                 
435         DEBUG(8,("print_subpath_values_environments: Exit\n"));
436         
437         return regval_ctr_numvals( val );
438 }
439
440
441 /**********************************************************************
442  handle enumeration of subkeys below KEY_PRINTING\Forms
443  Really just a stub function, but left here in case it needs to
444  be expanded later on
445  *********************************************************************/
446  
447 static int print_subpath_forms( char *key, REGSUBKEY_CTR *subkeys )
448 {
449         DEBUG(10,("print_subpath_forms: key=>[%s]\n", key ? key : "NULL" ));
450         
451         /* there are no subkeys */
452         
453         if ( key )
454                 return -1;
455         
456         return 0;
457 }
458
459 /**********************************************************************
460  handle enumeration of values below KEY_PRINTING\Forms
461  *********************************************************************/
462  
463 static int print_subpath_values_forms( char *key, REGVAL_CTR *val )
464 {
465         int             num_values = 0;
466         uint32          data[8];
467         int             form_index = 1;
468         
469         DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
470         
471         /* handle ..\Forms\ */
472         
473         if ( !key )
474         {
475                 nt_forms_struct *forms_list = NULL;
476                 nt_forms_struct *form = NULL;
477                 int i;
478                 
479                 if ( (num_values = get_ntforms( &forms_list )) == 0 ) 
480                         return 0;
481                 
482                 DEBUG(10,("print_subpath_values_forms: [%d] user defined forms returned\n",
483                         num_values));
484
485                 /* handle user defined forms */
486                                 
487                 for ( i=0; i<num_values; i++ )
488                 {
489                         form = &forms_list[i];
490                         
491                         data[0] = form->width;
492                         data[1] = form->length;
493                         data[2] = form->left;
494                         data[3] = form->top;
495                         data[4] = form->right;
496                         data[5] = form->bottom;
497                         data[6] = form_index++;
498                         data[7] = form->flag;
499                         
500                         regval_ctr_addvalue( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
501                 
502                 }
503                 
504                 SAFE_FREE( forms_list );
505                 forms_list = NULL;
506                 
507                 /* handle built-on forms */
508                 
509                 if ( (num_values = get_builtin_ntforms( &forms_list )) == 0 ) 
510                         return 0;
511                 
512                 DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n",
513                         num_values));
514                         
515                 for ( i=0; i<num_values; i++ )
516                 {
517                         form = &forms_list[i];
518                         
519                         data[0] = form->width;
520                         data[1] = form->length;
521                         data[2] = form->left;
522                         data[3] = form->top;
523                         data[4] = form->right;
524                         data[5] = form->bottom;
525                         data[6] = form_index++;
526                         data[7] = form->flag;
527                                         
528                         regval_ctr_addvalue( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
529                 }
530                 
531                 SAFE_FREE( forms_list );
532         }
533         
534         return num_values;
535 }
536
537 /**********************************************************************
538  handle enumeration of subkeys below KEY_PRINTING\Printers
539  *********************************************************************/
540  
541 static int print_subpath_printers( char *key, REGSUBKEY_CTR *subkeys )
542 {
543         int n_services = lp_numservices();      
544         int snum;
545         fstring sname;
546         int i;
547         int num_subkeys = 0;
548         char *keystr, *key2 = NULL;
549         char *base, *new_path;
550         NT_PRINTER_INFO_LEVEL *printer = NULL;
551         fstring *subkey_names = NULL;
552         
553         DEBUG(10,("print_subpath_printers: key=>[%s]\n", key ? key : "NULL" ));
554         
555         if ( !key )
556         {
557                 /* enumerate all printers */
558                 
559                 for (snum=0; snum<n_services; snum++) {
560                         if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
561                                 continue;
562
563                         /* don't report the [printers] share */
564
565                         if ( strequal( lp_servicename(snum), PRINTERS_NAME ) )
566                                 continue;
567                                 
568                         fstrcpy( sname, lp_servicename(snum) );
569                                 
570                         regsubkey_ctr_addkey( subkeys, sname );
571                 }
572                 
573                 num_subkeys = regsubkey_ctr_numkeys( subkeys );
574                 goto done;
575         }
576
577         /* get information for a specific printer */
578         
579         key2 = SMB_STRDUP( key );
580         keystr = key2;
581         reg_split_path( keystr, &base, &new_path );
582
583                 if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, base) ) )
584                 goto done;
585
586         num_subkeys = get_printer_subkeys( &printer->info_2->data, new_path?new_path:"", &subkey_names );
587         
588         for ( i=0; i<num_subkeys; i++ )
589                 regsubkey_ctr_addkey( subkeys, subkey_names[i] );
590         
591         free_a_printer( &printer, 2 );
592                         
593         /* no other subkeys below here */
594
595 done:   
596         SAFE_FREE( key2 );
597         SAFE_FREE( subkey_names );
598         
599         return num_subkeys;
600 }
601
602 /**********************************************************************
603  handle enumeration of values below KEY_PRINTING\Printers
604  *********************************************************************/
605  
606 static int print_subpath_values_printers( char *key, REGVAL_CTR *val )
607 {
608         int             num_values = 0;
609         char            *keystr, *key2 = NULL;
610         char            *base, *new_path;
611         NT_PRINTER_INFO_LEVEL   *printer = NULL;
612         NT_PRINTER_INFO_LEVEL_2 *info2;
613         DEVICEMODE      *devmode;
614         prs_struct      prs;
615         uint32          offset;
616         int             snum;
617         fstring         printername; 
618         NT_PRINTER_DATA *p_data;
619         int             i, key_index;
620         UNISTR2         data;
621         
622         /* 
623          * Theres are tw cases to deal with here
624          * (1) enumeration of printer_info_2 values
625          * (2) enumeration of the PrinterDriverData subney
626          */
627          
628         if ( !key ) {
629                 /* top level key has no values */
630                 goto done;
631         }
632         
633         key2 = SMB_STRDUP( key );
634         keystr = key2;
635         reg_split_path( keystr, &base, &new_path );
636         
637         fstrcpy( printername, base );
638         
639         if ( !new_path ) {
640                 char *p;
641                 uint32 printer_status = PRINTER_STATUS_OK;
642
643                 /* we are dealing with the printer itself */
644
645                 if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
646                         goto done;
647
648                 info2 = printer->info_2;
649                 
650
651                 regval_ctr_addvalue( val, "Attributes",       REG_DWORD, (char*)&info2->attributes,       sizeof(info2->attributes) );
652                 regval_ctr_addvalue( val, "Priority",         REG_DWORD, (char*)&info2->priority,         sizeof(info2->attributes) );
653                 regval_ctr_addvalue( val, "ChangeID",         REG_DWORD, (char*)&info2->changeid,         sizeof(info2->changeid) );
654                 regval_ctr_addvalue( val, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
655
656                 /* lie and say everything is ok since we don't want to call print_queue_length() to get the real status */
657                 regval_ctr_addvalue( val, "Status",           REG_DWORD, (char*)&printer_status,          sizeof(info2->status) );
658
659                 regval_ctr_addvalue( val, "StartTime",        REG_DWORD, (char*)&info2->starttime,        sizeof(info2->starttime) );
660                 regval_ctr_addvalue( val, "UntilTime",        REG_DWORD, (char*)&info2->untiltime,        sizeof(info2->untiltime) );
661
662                 /* strip the \\server\ from this string */
663                 if ( !(p = strrchr( info2->printername, '\\' ) ) )
664                         p = info2->printername;
665                 else
666                         p++;
667                 init_unistr2( &data, p, UNI_STR_TERMINATE);
668                 regval_ctr_addvalue( val, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
669
670                 init_unistr2( &data, info2->location, UNI_STR_TERMINATE);
671                 regval_ctr_addvalue( val, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
672
673                 init_unistr2( &data, info2->comment, UNI_STR_TERMINATE);
674                 regval_ctr_addvalue( val, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
675
676                 init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE);
677                 regval_ctr_addvalue( val, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
678
679                 init_unistr2( &data, info2->portname, UNI_STR_TERMINATE);
680                 regval_ctr_addvalue( val, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
681
682                 init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE);
683                 regval_ctr_addvalue( val, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
684
685                 init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE);
686                 regval_ctr_addvalue( val, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
687
688                 init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE);
689                 regval_ctr_addvalue( val, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
690
691                 init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE);
692                 regval_ctr_addvalue( val, "Print Processor",  REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
693
694                 init_unistr2( &data, "RAW", UNI_STR_TERMINATE);
695                 regval_ctr_addvalue( val, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
696
697                 
698                 /* use a prs_struct for converting the devmode and security 
699                    descriptor to REG_BINARY */
700                 
701                 prs_init( &prs, MAX_PDU_FRAG_LEN, regval_ctr_getctx(val), MARSHALL);
702
703                 /* stream the device mode */
704                 
705                 snum = lp_servicenumber(info2->sharename);
706                 if ( (devmode = construct_dev_mode( snum )) != NULL )
707                 {                       
708                         if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
709                         
710                                 offset = prs_offset( &prs );
711                                 
712                                 regval_ctr_addvalue( val, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
713                         }
714                         
715                         
716                 }
717                 
718                 prs_mem_clear( &prs );
719                 prs_set_offset( &prs, 0 );
720                 
721                 if ( info2->secdesc_buf && info2->secdesc_buf->len ) 
722                 {
723                         if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) {
724                         
725                                 offset = prs_offset( &prs );
726                         
727                                 regval_ctr_addvalue( val, "Security", REG_BINARY, prs_data_p(&prs), offset );
728                         }
729                 }
730
731                 prs_mem_free( &prs );
732                 
733                 num_values = regval_ctr_numvals( val ); 
734                 
735                 goto done;
736                 
737         }
738                 
739         /* now enumerate the key */
740         
741         if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
742                 goto done;
743         
744         /* iterate over all printer data and fill the regval container */
745         
746         p_data = &printer->info_2->data;
747         if ( (key_index = lookup_printerkey( p_data, new_path )) == -1  ) {
748                 DEBUG(10,("print_subpath_values_printer: Unknown keyname [%s]\n", new_path));
749                 goto done;
750         }
751         
752         num_values = regval_ctr_numvals( &p_data->keys[key_index].values );
753         
754         for ( i=0; i<num_values; i++ )
755                 regval_ctr_copyvalue( val, regval_ctr_specific_value(&p_data->keys[key_index].values, i) );
756                         
757
758 done:
759         if ( printer )
760                 free_a_printer( &printer, 2 );
761                 
762         SAFE_FREE( key2 ); 
763         
764         return num_values;
765 }
766
767 /**********************************************************************
768  Routine to handle enumeration of subkeys and values 
769  below KEY_PRINTING (depending on whether or not subkeys/val are 
770  valid pointers. 
771  *********************************************************************/
772  
773 static int handle_printing_subpath( char *key, REGSUBKEY_CTR *subkeys, REGVAL_CTR *val )
774 {
775         int result = 0;
776         char *p, *base;
777         int i;
778         
779         DEBUG(10,("handle_printing_subpath: key=>[%s]\n", key ));
780         
781         /* 
782          * break off the first part of the path 
783          * topmost base **must** be one of the strings 
784          * in top_level_keys[]
785          */
786         
787         reg_split_path( key, &base, &p);
788                 
789         for ( i=0; i<MAX_TOP_LEVEL_KEYS; i++ ) {
790                 if ( StrCaseCmp( top_level_keys[i], base ) == 0 )
791                         break;
792         }
793         
794         DEBUG(10,("handle_printing_subpath: base=>[%s], i==[%d]\n", base, i));  
795                 
796         if ( !(i < MAX_TOP_LEVEL_KEYS) )
797                 return -1;
798                                                 
799         /* Call routine to handle each top level key */
800         switch ( i )
801         {
802                 case KEY_INDEX_ENVIR:
803                         if ( subkeys )
804                                 print_subpath_environments( p, subkeys );
805                         if ( val )
806                                 print_subpath_values_environments( p, val );
807                         break;
808                 
809                 case KEY_INDEX_FORMS:
810                         if ( subkeys )
811                                 print_subpath_forms( p, subkeys );
812                         if ( val )
813                                 print_subpath_values_forms( p, val );
814                         break;
815                         
816                 case KEY_INDEX_PRINTER:
817                         if ( subkeys )
818                                 print_subpath_printers( p, subkeys );
819                         if ( val )
820                                 print_subpath_values_printers( p, val );
821                         break;
822         
823                 /* default case for top level key that has no handler */
824                 
825                 default:
826                         break;
827         }
828         
829         
830         
831         return result;
832
833 }
834
835 /**********************************************************************
836  Enumerate registry subkey names given a registry path.  
837  Caller is responsible for freeing memory to **subkeys
838  *********************************************************************/
839  
840 static int printing_subkey_info( const char *key, REGSUBKEY_CTR *subkey_ctr )
841 {
842         char            *path;
843         int             num_subkeys = 0;
844         
845         DEBUG(10,("printing_subkey_info: key=>[%s]\n", key));
846         
847         path = trim_reg_path( key );
848         
849         /* check to see if we are dealing with the top level key */
850         
851         if ( path ) {
852                 num_subkeys = handle_printing_subpath( path, subkey_ctr, NULL );
853                 SAFE_FREE( path );
854                 return num_subkeys;
855         }
856         
857         /* handle top level keys here */
858                 
859         if ( strequal( KEY_PRINTING, key ) ) {
860                 regsubkey_ctr_addkey( subkey_ctr, "Environments" );
861                 regsubkey_ctr_addkey( subkey_ctr, "Forms" );
862         }
863         else if ( strequal( KEY_PRINTING_2K, key ) ) {
864                 regsubkey_ctr_addkey( subkey_ctr, "Printers" );
865         }
866
867         return num_subkeys;
868 }
869
870 /**********************************************************************
871  Enumerate registry values given a registry path.  
872  Caller is responsible for freeing memory 
873  *********************************************************************/
874
875 static int printing_value_info( const char *key, REGVAL_CTR *val )
876 {
877         char            *path;
878         int             num_values = 0;
879         
880         DEBUG(10,("printing_value_info: key=>[%s]\n", key));
881         
882         path = trim_reg_path( key );
883                 
884         if ( path ) {
885                 num_values = handle_printing_subpath( path, NULL, val );
886                 SAFE_FREE( path );
887                 return num_values;
888         }
889         
890         /* top level key */
891         
892         if ( strequal( key, KEY_PRINTING_PORTS ) ) 
893                 num_values = fill_ports_values( val );
894         
895         return num_values;
896 }
897
898 /**********************************************************************
899  Stub function which always returns failure since we don't want
900  people storing printing information directly via regostry calls
901  (for now at least)
902  *********************************************************************/
903
904 static BOOL printing_store_subkey( const char *key, REGSUBKEY_CTR *subkeys )
905 {
906         return True;
907 }
908
909 /**********************************************************************
910  Stub function which always returns failure since we don't want
911  people storing printing information directly via regostry calls
912  (for now at least)
913  *********************************************************************/
914
915 static BOOL printing_store_value( const char *key, REGVAL_CTR *val )
916 {
917         return True;
918 }
919
920 /* 
921  * Table of function pointers for accessing printing data
922  */
923  
924 REGISTRY_OPS printing_ops = {
925         printing_subkey_info,
926         printing_value_info,
927         printing_store_subkey,
928         printing_store_value,
929         NULL
930 };
931
932