diff options
Diffstat (limited to 'source3/registry/reg_backend_printing.c')
-rw-r--r-- | source3/registry/reg_backend_printing.c | 1269 |
1 files changed, 1269 insertions, 0 deletions
diff --git a/source3/registry/reg_backend_printing.c b/source3/registry/reg_backend_printing.c new file mode 100644 index 0000000000..a4da103d40 --- /dev/null +++ b/source3/registry/reg_backend_printing.c @@ -0,0 +1,1269 @@ +/* + * Unix SMB/CIFS implementation. + * Virtual Windows Registry Layer + * Copyright (C) Gerald Carter 2002-2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* Implementation of registry virtual views for printing information */ + +#include "includes.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_REGISTRY + +/* registrt paths used in the print_registry[] */ + +#define KEY_MONITORS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/MONITORS" +#define KEY_FORMS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS" +#define KEY_CONTROL_PRINTERS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS" +#define KEY_ENVIRONMENTS "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS" +#define KEY_CONTROL_PRINT "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT" +#define KEY_WINNT_PRINTERS "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS" +#define KEY_WINNT_PRINT "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT" +#define KEY_PORTS "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PORTS" + +/* callback table for various registry paths below the ones we service in this module */ + +struct reg_dyn_tree { + /* full key path in normalized form */ + const char *path; + + /* callbscks for fetch/store operations */ + int ( *fetch_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys ); + bool (*store_subkeys) ( const char *path, REGSUBKEY_CTR *subkeys ); + int (*fetch_values) ( const char *path, REGVAL_CTR *values ); + bool (*store_values) ( const char *path, REGVAL_CTR *values ); +}; + +/********************************************************************* + ********************************************************************* + ** Utility Functions + ********************************************************************* + *********************************************************************/ + +/*********************************************************************** + simple function to prune a pathname down to the basename of a file + **********************************************************************/ + +static const char *dos_basename(const char *path) +{ + const char *p; + + if (!(p = strrchr( path, '\\'))) { + p = path; + } else { + p++; + } + + return p; +} + +/********************************************************************* + ********************************************************************* + ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/FORMS" + ********************************************************************* + *********************************************************************/ + +static int key_forms_fetch_keys(const char *key, REGSUBKEY_CTR *subkeys) +{ + char *p = reg_remaining_path(talloc_tos(), key + strlen(KEY_FORMS)); + + /* no keys below Forms */ + + if (p) { + return -1; + } + + return 0; +} + +/********************************************************************** + *********************************************************************/ + +static int key_forms_fetch_values( const char *key, REGVAL_CTR *values ) +{ + uint32 data[8]; + int i, num_values, form_index = 1; + nt_forms_struct *forms_list = NULL; + nt_forms_struct *form; + + DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" )); + + num_values = get_ntforms( &forms_list ); + + DEBUG(10,("hive_forms_fetch_values: [%d] user defined forms returned\n", + num_values)); + + /* handle user defined forms */ + + for ( i=0; i<num_values; i++ ) { + form = &forms_list[i]; + + data[0] = form->width; + data[1] = form->length; + data[2] = form->left; + data[3] = form->top; + data[4] = form->right; + data[5] = form->bottom; + data[6] = form_index++; + data[7] = form->flag; + + regval_ctr_addvalue( values, form->name, REG_BINARY, (char*)data, sizeof(data) ); + } + + SAFE_FREE( forms_list ); + forms_list = NULL; + + /* handle built-on forms */ + + num_values = get_builtin_ntforms( &forms_list ); + + DEBUG(10,("print_subpath_values_forms: [%d] built-in forms returned\n", + num_values)); + + for ( i=0; i<num_values; i++ ) { + form = &forms_list[i]; + + data[0] = form->width; + data[1] = form->length; + data[2] = form->left; + data[3] = form->top; + data[4] = form->right; + data[5] = form->bottom; + data[6] = form_index++; + data[7] = form->flag; + + regval_ctr_addvalue(values, form->name, REG_BINARY, (char*)data, sizeof(data) ); + } + + SAFE_FREE(forms_list); + + return regval_ctr_numvals(values); +} + +/********************************************************************* + ********************************************************************* + ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/PRINTERS" + ** "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PRINT/PRINTERS" + ********************************************************************* + *********************************************************************/ + +/********************************************************************* + strip off prefix for printers key. DOes return a pointer to static + memory. + *********************************************************************/ + +static char *strip_printers_prefix(const char *key) +{ + char *subkeypath = NULL; + char *path = NULL; + TALLOC_CTX *ctx = talloc_tos(); + + path = talloc_strdup(ctx, key); + if (!path) { + return NULL; + } + path = normalize_reg_path(ctx, path); + if (!path) { + return NULL; + } + + /* normalizing the path does not change length, just key delimiters and case */ + + if (strncmp(path, KEY_WINNT_PRINTERS, strlen(KEY_WINNT_PRINTERS)) == 0) { + subkeypath = reg_remaining_path(ctx, key + strlen(KEY_WINNT_PRINTERS)); + } else { + subkeypath = reg_remaining_path(ctx, key + strlen(KEY_CONTROL_PRINTERS)); + } + + TALLOC_FREE(path); + return subkeypath; +} + +/********************************************************************* + *********************************************************************/ + +static int key_printers_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys ) +{ + int n_services = lp_numservices(); + int snum; + fstring sname; + int i; + int num_subkeys = 0; + char *printers_key; + char *printername, *printerdatakey; + NT_PRINTER_INFO_LEVEL *printer = NULL; + fstring *subkey_names = NULL; + + DEBUG(10,("key_printers_fetch_keys: key=>[%s]\n", key ? key : "NULL" )); + + printers_key = strip_printers_prefix( key ); + + if ( !printers_key ) { + /* enumerate all printers */ + + for (snum=0; snum<n_services; snum++) { + if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) ) + continue; + + /* don't report the [printers] share */ + + if ( strequal( lp_servicename(snum), PRINTERS_NAME ) ) + continue; + + fstrcpy( sname, lp_servicename(snum) ); + + regsubkey_ctr_addkey( subkeys, sname ); + } + + num_subkeys = regsubkey_ctr_numkeys( subkeys ); + goto done; + } + + /* get information for a specific printer */ + + if (!reg_split_path( printers_key, &printername, &printerdatakey )) { + return -1; + } + + /* validate the printer name */ + + for (snum=0; snum<n_services; snum++) { + if ( !lp_snum_ok(snum) || !lp_print_ok(snum) ) + continue; + if (strequal( lp_servicename(snum), printername ) ) + break; + } + + if ( snum>=n_services + || !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) ) + { + return -1; + } + + num_subkeys = get_printer_subkeys( printer->info_2->data, printerdatakey?printerdatakey:"", &subkey_names ); + + for ( i=0; i<num_subkeys; i++ ) + regsubkey_ctr_addkey( subkeys, subkey_names[i] ); + + free_a_printer( &printer, 2 ); + + /* no other subkeys below here */ + +done: + SAFE_FREE( subkey_names ); + + return num_subkeys; +} + +/********************************************************************** + Take a list of names and call add_printer_hook() if necessary + Note that we do this a little differently from Windows since the + keyname is the sharename and not the printer name. + *********************************************************************/ + +static bool add_printers_by_registry( REGSUBKEY_CTR *subkeys ) +{ + int i, num_keys, snum; + char *printername; + NT_PRINTER_INFO_LEVEL_2 info2; + NT_PRINTER_INFO_LEVEL printer; + + ZERO_STRUCT( info2 ); + printer.info_2 = &info2; + + num_keys = regsubkey_ctr_numkeys( subkeys ); + + become_root(); + for ( i=0; i<num_keys; i++ ) { + printername = regsubkey_ctr_specific_key( subkeys, i ); + snum = find_service( printername ); + + /* just verify a valied snum for now */ + if ( snum == -1 ) { + fstrcpy( info2.printername, printername ); + fstrcpy( info2.sharename, printername ); + if ( !add_printer_hook(talloc_tos(), NULL, &printer ) ) { + DEBUG(0,("add_printers_by_registry: Failed to add printer [%s]\n", + printername)); + } + } + } + unbecome_root(); + + return True; +} + +/********************************************************************** + *********************************************************************/ + +static bool key_printers_store_keys( const char *key, REGSUBKEY_CTR *subkeys ) +{ + char *printers_key; + char *printername, *printerdatakey; + NT_PRINTER_INFO_LEVEL *printer = NULL; + int i, num_subkeys, num_existing_keys; + char *subkeyname; + fstring *existing_subkeys = NULL; + + printers_key = strip_printers_prefix( key ); + + if ( !printers_key ) { + /* have to deal with some new or deleted printer */ + return add_printers_by_registry( subkeys ); + } + + if (!reg_split_path( printers_key, &printername, &printerdatakey )) { + return False; + } + + /* lookup the printer */ + + if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, printername)) ) { + DEBUG(0,("key_printers_store_keys: Tried to store subkey for bad printername %s\n", + printername)); + return False; + } + + /* get the top level printer keys */ + + num_existing_keys = get_printer_subkeys( printer->info_2->data, "", &existing_subkeys ); + + for ( i=0; i<num_existing_keys; i++ ) { + + /* remove the key if it has been deleted */ + + if ( !regsubkey_ctr_key_exists( subkeys, existing_subkeys[i] ) ) { + DEBUG(5,("key_printers_store_keys: deleting key %s\n", + existing_subkeys[i])); + delete_printer_key( printer->info_2->data, existing_subkeys[i] ); + } + } + + num_subkeys = regsubkey_ctr_numkeys( subkeys ); + for ( i=0; i<num_subkeys; i++ ) { + subkeyname = regsubkey_ctr_specific_key(subkeys, i); + /* add any missing printer keys */ + if ( lookup_printerkey(printer->info_2->data, subkeyname) == -1 ) { + DEBUG(5,("key_printers_store_keys: adding key %s\n", + existing_subkeys[i])); + if ( add_new_printer_key( printer->info_2->data, subkeyname ) == -1 ) { + SAFE_FREE( existing_subkeys ); + return False; + } + } + } + + /* write back to disk */ + + mod_a_printer( printer, 2 ); + + /* cleanup */ + + if ( printer ) + free_a_printer( &printer, 2 ); + + SAFE_FREE( existing_subkeys ); + + return True; +} + +/********************************************************************** + *********************************************************************/ + +static void fill_in_printer_values( NT_PRINTER_INFO_LEVEL_2 *info2, REGVAL_CTR *values ) +{ + DEVICEMODE *devmode; + prs_struct prs; + uint32 offset; + UNISTR2 data; + char *p; + uint32 printer_status = PRINTER_STATUS_OK; + + regval_ctr_addvalue( values, "Attributes", REG_DWORD, (char*)&info2->attributes, sizeof(info2->attributes) ); + regval_ctr_addvalue( values, "Priority", REG_DWORD, (char*)&info2->priority, sizeof(info2->attributes) ); + regval_ctr_addvalue( values, "ChangeID", REG_DWORD, (char*)&info2->changeid, sizeof(info2->changeid) ); + regval_ctr_addvalue( values, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) ); + + /* lie and say everything is ok since we don't want to call print_queue_length() to get the real status */ + regval_ctr_addvalue( values, "Status", REG_DWORD, (char*)&printer_status, sizeof(info2->status) ); + + regval_ctr_addvalue( values, "StartTime", REG_DWORD, (char*)&info2->starttime, sizeof(info2->starttime) ); + regval_ctr_addvalue( values, "UntilTime", REG_DWORD, (char*)&info2->untiltime, sizeof(info2->untiltime) ); + + /* strip the \\server\ from this string */ + if ( !(p = strrchr( info2->printername, '\\' ) ) ) + p = info2->printername; + else + p++; + init_unistr2( &data, p, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, info2->location, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, info2->comment, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, info2->portname, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Print Processor", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, "RAW", UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + + /* use a prs_struct for converting the devmode and security + descriptor to REG_BINARY */ + + prs_init( &prs, RPC_MAX_PDU_FRAG_LEN, values, MARSHALL); + + /* stream the device mode */ + + if ( (devmode = construct_dev_mode( info2->sharename )) != NULL ) { + if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) { + offset = prs_offset( &prs ); + regval_ctr_addvalue( values, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset ); + } + } + + prs_mem_clear( &prs ); + prs_set_offset( &prs, 0 ); + + /* stream the printer security descriptor */ + + if ( info2->secdesc_buf && + info2->secdesc_buf->sd && + info2->secdesc_buf->sd_size ) + { + if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sd, &prs, 0 ) ) { + offset = prs_offset( &prs ); + regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&prs), offset ); + } + } + + prs_mem_free( &prs ); + + return; +} + +/********************************************************************** + *********************************************************************/ + +static int key_printers_fetch_values( const char *key, REGVAL_CTR *values ) +{ + int num_values; + char *printers_key; + char *printername, *printerdatakey; + NT_PRINTER_INFO_LEVEL *printer = NULL; + NT_PRINTER_DATA *p_data; + int i, key_index; + + printers_key = strip_printers_prefix( key ); + + /* top level key values stored in the registry has no values */ + + if ( !printers_key ) { + /* normalize to the 'HKLM\SOFTWARE\...\Print\Printers' key */ + return regdb_fetch_values( KEY_WINNT_PRINTERS, values ); + } + + /* lookup the printer object */ + + if (!reg_split_path( printers_key, &printername, &printerdatakey )) { + return -1; + } + + if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) ) + goto done; + + if ( !printerdatakey ) { + fill_in_printer_values( printer->info_2, values ); + goto done; + } + + /* iterate over all printer data keys and fill the regval container */ + + p_data = printer->info_2->data; + if ( (key_index = lookup_printerkey( p_data, printerdatakey )) == -1 ) { + /* failure....should never happen if the client has a valid open handle first */ + DEBUG(10,("key_printers_fetch_values: Unknown keyname [%s]\n", printerdatakey)); + if ( printer ) + free_a_printer( &printer, 2 ); + return -1; + } + + num_values = regval_ctr_numvals( p_data->keys[key_index].values ); + for ( i=0; i<num_values; i++ ) + regval_ctr_copyvalue( values, regval_ctr_specific_value(p_data->keys[key_index].values, i) ); + + +done: + if ( printer ) + free_a_printer( &printer, 2 ); + + return regval_ctr_numvals( values ); +} + +/********************************************************************** + *********************************************************************/ + +#define REG_IDX_ATTRIBUTES 1 +#define REG_IDX_PRIORITY 2 +#define REG_IDX_DEFAULT_PRIORITY 3 +#define REG_IDX_CHANGEID 4 +#define REG_IDX_STATUS 5 +#define REG_IDX_STARTTIME 6 +#define REG_IDX_NAME 7 +#define REG_IDX_LOCATION 8 +#define REG_IDX_DESCRIPTION 9 +#define REG_IDX_PARAMETERS 10 +#define REG_IDX_PORT 12 +#define REG_IDX_SHARENAME 13 +#define REG_IDX_DRIVER 14 +#define REG_IDX_SEP_FILE 15 +#define REG_IDX_PRINTPROC 16 +#define REG_IDX_DATATYPE 17 +#define REG_IDX_DEVMODE 18 +#define REG_IDX_SECDESC 19 +#define REG_IDX_UNTILTIME 20 + +struct { + const char *name; + int index; +} printer_values_map[] = { + { "Attributes", REG_IDX_ATTRIBUTES }, + { "Priority", REG_IDX_PRIORITY }, + { "Default Priority", REG_IDX_DEFAULT_PRIORITY }, + { "ChangeID", REG_IDX_CHANGEID }, + { "Status", REG_IDX_STATUS }, + { "StartTime", REG_IDX_STARTTIME }, + { "UntilTime", REG_IDX_UNTILTIME }, + { "Name", REG_IDX_NAME }, + { "Location", REG_IDX_LOCATION }, + { "Description", REG_IDX_DESCRIPTION }, + { "Parameters", REG_IDX_PARAMETERS }, + { "Port", REG_IDX_PORT }, + { "Share Name", REG_IDX_SHARENAME }, + { "Printer Driver", REG_IDX_DRIVER }, + { "Separator File", REG_IDX_SEP_FILE }, + { "Print Processor", REG_IDX_PRINTPROC }, + { "Datatype", REG_IDX_DATATYPE }, + { "Default Devmode", REG_IDX_DEVMODE }, + { "Security", REG_IDX_SECDESC }, + { NULL, -1 } +}; + + +static int find_valuename_index( const char *valuename ) +{ + int i; + + for ( i=0; printer_values_map[i].name; i++ ) { + if ( strequal( valuename, printer_values_map[i].name ) ) + return printer_values_map[i].index; + } + + return -1; +} + +/********************************************************************** + *********************************************************************/ + +static void convert_values_to_printer_info_2( NT_PRINTER_INFO_LEVEL_2 *printer2, REGVAL_CTR *values ) +{ + int num_values = regval_ctr_numvals( values ); + uint32 value_index; + REGISTRY_VALUE *val; + int i; + + for ( i=0; i<num_values; i++ ) { + val = regval_ctr_specific_value( values, i ); + value_index = find_valuename_index( regval_name( val ) ); + + switch( value_index ) { + case REG_IDX_ATTRIBUTES: + printer2->attributes = (uint32)(*regval_data_p(val)); + break; + case REG_IDX_PRIORITY: + printer2->priority = (uint32)(*regval_data_p(val)); + break; + case REG_IDX_DEFAULT_PRIORITY: + printer2->default_priority = (uint32)(*regval_data_p(val)); + break; + case REG_IDX_CHANGEID: + printer2->changeid = (uint32)(*regval_data_p(val)); + break; + case REG_IDX_STARTTIME: + printer2->starttime = (uint32)(*regval_data_p(val)); + break; + case REG_IDX_UNTILTIME: + printer2->untiltime = (uint32)(*regval_data_p(val)); + break; + case REG_IDX_NAME: + rpcstr_pull( printer2->printername, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_LOCATION: + rpcstr_pull( printer2->location, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_DESCRIPTION: + rpcstr_pull( printer2->comment, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_PARAMETERS: + rpcstr_pull( printer2->parameters, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_PORT: + rpcstr_pull( printer2->portname, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_SHARENAME: + rpcstr_pull( printer2->sharename, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_DRIVER: + rpcstr_pull( printer2->drivername, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_SEP_FILE: + rpcstr_pull( printer2->sepfile, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_PRINTPROC: + rpcstr_pull( printer2->printprocessor, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_DATATYPE: + rpcstr_pull( printer2->datatype, regval_data_p(val), sizeof(fstring), regval_size(val), 0 ); + break; + case REG_IDX_DEVMODE: + break; + case REG_IDX_SECDESC: + break; + default: + /* unsupported value...throw away */ + DEBUG(8,("convert_values_to_printer_info_2: Unsupported registry value [%s]\n", + regval_name( val ) )); + } + } + + return; +} + +/********************************************************************** + *********************************************************************/ + +static bool key_printers_store_values( const char *key, REGVAL_CTR *values ) +{ + char *printers_key; + char *printername, *keyname; + NT_PRINTER_INFO_LEVEL *printer = NULL; + WERROR result; + + printers_key = strip_printers_prefix( key ); + + /* values in the top level key get stored in the registry */ + + if ( !printers_key ) { + /* normalize on the 'HKLM\SOFTWARE\....\Print\Printers' key */ + return regdb_store_values( KEY_WINNT_PRINTERS, values ); + } + + if (!reg_split_path( printers_key, &printername, &keyname )) { + return False; + } + + if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, printername) ) ) + return False; + + /* deal with setting values directly under the printername */ + + if ( !keyname ) { + convert_values_to_printer_info_2( printer->info_2, values ); + } + else { + int num_values = regval_ctr_numvals( values ); + int i; + REGISTRY_VALUE *val; + + delete_printer_key( printer->info_2->data, keyname ); + + /* deal with any subkeys */ + for ( i=0; i<num_values; i++ ) { + val = regval_ctr_specific_value( values, i ); + result = set_printer_dataex( printer, keyname, + regval_name( val ), + regval_type( val ), + regval_data_p( val ), + regval_size( val ) ); + if ( !W_ERROR_IS_OK(result) ) { + DEBUG(0,("key_printers_store_values: failed to set printer data [%s]!\n", + keyname)); + free_a_printer( &printer, 2 ); + return False; + } + } + } + + result = mod_a_printer( printer, 2 ); + + free_a_printer( &printer, 2 ); + + return W_ERROR_IS_OK(result); +} + +/********************************************************************* + ********************************************************************* + ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT/ENVIRONMENTS" + ********************************************************************* + *********************************************************************/ + +static int key_driver_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys ) +{ + const char *environments[] = { + "Windows 4.0", + "Windows NT x86", + "Windows NT R4000", + "Windows NT Alpha_AXP", + "Windows NT PowerPC", + "Windows IA64", + "Windows x64", + NULL }; + fstring *drivers = NULL; + int i, env_index, num_drivers; + char *keystr, *base, *subkeypath; + char *key2 = NULL; + int num_subkeys = -1; + int version; + TALLOC_CTX *ctx = talloc_tos(); + + DEBUG(10,("key_driver_fetch_keys key=>[%s]\n", key ? key : "NULL" )); + + keystr = reg_remaining_path(ctx, key + strlen(KEY_ENVIRONMENTS) ); + + /* list all possible architectures */ + + if ( !keystr ) { + for ( num_subkeys=0; environments[num_subkeys]; num_subkeys++ ) + regsubkey_ctr_addkey( subkeys, environments[num_subkeys] ); + + return num_subkeys; + } + + /* we are dealing with a subkey of "Environments */ + key2 = talloc_strdup(ctx, keystr); + if (!key2) { + return -1; + } + keystr = key2; + if (!reg_split_path(keystr, &base, &subkeypath )) { + return -1; + } + + /* sanity check */ + + for ( env_index=0; environments[env_index]; env_index++ ) { + if ( strequal( environments[env_index], base ) ) + break; + } + if ( !environments[env_index] ) + return -1; + + /* ...\Print\Environements\...\ */ + + if ( !subkeypath ) { + regsubkey_ctr_addkey( subkeys, "Drivers" ); + regsubkey_ctr_addkey( subkeys, "Print Processors" ); + + return 2; + } + + /* more of the key path to process */ + + keystr = subkeypath; + if (!reg_split_path( keystr, &base, &subkeypath )) { + return -1; + } + + /* ...\Print\Environements\...\Drivers\ */ + + if ( !subkeypath ) { + if ( strequal(base, "Drivers") ) { + switch ( env_index ) { + case 0: /* Win9x */ + regsubkey_ctr_addkey( subkeys, "Version-0" ); + break; + default: /* Windows NT based systems */ + regsubkey_ctr_addkey( subkeys, "Version-2" ); + regsubkey_ctr_addkey( subkeys, "Version-3" ); + break; + } + + return regsubkey_ctr_numkeys( subkeys ); + } else if ( strequal(base, "Print Processors") ) { + if ( env_index == 1 || env_index == 5 || env_index == 6 ) + + + return regsubkey_ctr_numkeys( subkeys ); + } else + return -1; /* bad path */ + } + + /* we finally get to enumerate the drivers */ + + /* only one possible subkey below PrintProc key */ + + if ( strequal(base, "Print Processors") ) { + keystr = subkeypath; + if (!reg_split_path( keystr, &base, &subkeypath )) { + return -1; + } + + /* no subkeys below this point */ + + if ( subkeypath ) + return -1; + + /* only allow one keyname here -- 'winprint' */ + + return strequal( base, "winprint" ) ? 0 : -1; + } + + /* only dealing with drivers from here on out */ + + keystr = subkeypath; + if (!reg_split_path( keystr, &base, &subkeypath )) { + return -1; + } + + version = atoi(&base[strlen(base)-1]); + + switch (env_index) { + case 0: + if ( version != 0 ) + return -1; + break; + default: + if ( version != 2 && version != 3 ) + return -1; + break; + } + + + if ( !subkeypath ) { + num_drivers = get_ntdrivers( &drivers, environments[env_index], version ); + for ( i=0; i<num_drivers; i++ ) + regsubkey_ctr_addkey( subkeys, drivers[i] ); + + return regsubkey_ctr_numkeys( subkeys ); + } + + /* if anything else left, just say if has no subkeys */ + + DEBUG(1,("key_driver_fetch_keys unhandled key [%s] (subkey == %s\n", + key, subkeypath )); + + return 0; +} + + +/********************************************************************** + *********************************************************************/ + +static void fill_in_driver_values( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3, REGVAL_CTR *values ) +{ + char *buffer = NULL; + int buffer_size = 0; + int i, length; + const char *filename; + UNISTR2 data; + + filename = dos_basename( info3->driverpath ); + init_unistr2( &data, filename, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Driver", REG_SZ, (char*)data.buffer, + data.uni_str_len*sizeof(uint16) ); + + filename = dos_basename( info3->configfile ); + init_unistr2( &data, filename, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Configuration File", REG_SZ, (char*)data.buffer, + data.uni_str_len*sizeof(uint16) ); + + filename = dos_basename( info3->datafile ); + init_unistr2( &data, filename, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Data File", REG_SZ, (char*)data.buffer, + data.uni_str_len*sizeof(uint16) ); + + filename = dos_basename( info3->helpfile ); + init_unistr2( &data, filename, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Help File", REG_SZ, (char*)data.buffer, + data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE); + regval_ctr_addvalue( values, "Data Type", REG_SZ, (char*)data.buffer, + data.uni_str_len*sizeof(uint16) ); + + regval_ctr_addvalue( values, "Version", REG_DWORD, (char*)&info3->cversion, + sizeof(info3->cversion) ); + + if ( info3->dependentfiles ) { + /* place the list of dependent files in a single + character buffer, separating each file name by + a NULL */ + + for ( i=0; strcmp(info3->dependentfiles[i], ""); i++ ) { + /* strip the path to only the file's base name */ + + filename = dos_basename( info3->dependentfiles[i] ); + + length = strlen(filename); + + buffer = (char *)SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) ); + if ( !buffer ) { + break; + } + + init_unistr2( &data, filename, UNI_STR_TERMINATE); + memcpy( buffer+buffer_size, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + buffer_size += (length + 1)*sizeof(uint16); + } + + /* terminated by double NULL. Add the final one here */ + + buffer = (char *)SMB_REALLOC( buffer, buffer_size + 2 ); + if ( !buffer ) { + buffer_size = 0; + } else { + buffer[buffer_size++] = '\0'; + buffer[buffer_size++] = '\0'; + } + } + + regval_ctr_addvalue( values, "Dependent Files", REG_MULTI_SZ, buffer, buffer_size ); + + SAFE_FREE( buffer ); + + return; +} + +/********************************************************************** + *********************************************************************/ + +static int driver_arch_fetch_values( char *key, REGVAL_CTR *values ) +{ + char *keystr, *base, *subkeypath; + fstring arch_environment; + fstring driver; + int version; + NT_PRINTER_DRIVER_INFO_LEVEL driver_ctr; + WERROR w_result; + + if (!reg_split_path( key, &base, &subkeypath )) { + return -1; + } + + /* no values in 'Environments\Drivers\Windows NT x86' */ + + if ( !subkeypath ) + return 0; + + /* We have the Architecture string and some subkey name: + Currently we only support + * Drivers + * Print Processors + Anything else is an error. + */ + + fstrcpy( arch_environment, base ); + + keystr = subkeypath; + if (!reg_split_path( keystr, &base, &subkeypath )) { + return -1; + } + + if ( strequal(base, "Print Processors") ) + return 0; + + /* only Drivers key can be left */ + + if ( !strequal(base, "Drivers") ) + return -1; + + if ( !subkeypath ) + return 0; + + /* We know that we have Architechure\Drivers with some subkey name + The subkey name has to be Version-XX */ + + keystr = subkeypath; + if (!reg_split_path( keystr, &base, &subkeypath )) { + return -1; + } + + if ( !subkeypath ) + return 0; + + version = atoi(&base[strlen(base)-1]); + + /* BEGIN PRINTER DRIVER NAME BLOCK */ + + keystr = subkeypath; + if (!reg_split_path( keystr, &base, &subkeypath )) { + return -1; + } + + /* don't go any deeper for now */ + + fstrcpy( driver, base ); + + w_result = get_a_printer_driver( &driver_ctr, 3, driver, arch_environment, version ); + + if ( !W_ERROR_IS_OK(w_result) ) + return -1; + + fill_in_driver_values( driver_ctr.info_3, values ); + + free_a_printer_driver( driver_ctr, 3 ); + + /* END PRINTER DRIVER NAME BLOCK */ + + + DEBUG(8,("key_driver_fetch_values: Exit\n")); + + return regval_ctr_numvals( values ); +} + +/********************************************************************** + *********************************************************************/ + +static int key_driver_fetch_values( const char *key, REGVAL_CTR *values ) +{ + char *keystr = NULL; + char *subkey = NULL; + TALLOC_CTX *ctx = talloc_tos(); + + DEBUG(8,("key_driver_fetch_values: Enter key => [%s]\n", key ? key : "NULL")); + + /* no values in the Environments key */ + + if (!(keystr = reg_remaining_path(ctx, key + strlen(KEY_ENVIRONMENTS)))) + return 0; + + subkey = talloc_strdup(ctx, keystr); + if (!subkey) { + return 0; + } + + /* pass off to handle subkeys */ + + return driver_arch_fetch_values( subkey, values ); +} + +/********************************************************************* + ********************************************************************* + ** "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRINT" + ********************************************************************* + *********************************************************************/ + +static int key_print_fetch_keys( const char *key, REGSUBKEY_CTR *subkeys ) +{ + int key_len = strlen(key); + + /* no keys below 'Print' handled here */ + + if ( (key_len != strlen(KEY_CONTROL_PRINT)) && (key_len != strlen(KEY_WINNT_PRINT)) ) + return -1; + + regsubkey_ctr_addkey( subkeys, "Environments" ); + regsubkey_ctr_addkey( subkeys, "Monitors" ); + regsubkey_ctr_addkey( subkeys, "Forms" ); + regsubkey_ctr_addkey( subkeys, "Printers" ); + + return regsubkey_ctr_numkeys( subkeys ); +} + +/********************************************************************** + ********************************************************************* + ** Structure to hold dispatch table of ops for various printer keys. + ** Make sure to always store deeper keys along the same path first so + ** we ge a more specific match. + ********************************************************************* + *********************************************************************/ + +static struct reg_dyn_tree print_registry[] = { +/* just pass the monitor onto the registry tdb */ +{ KEY_MONITORS, + ®db_fetch_keys, + ®db_store_keys, + ®db_fetch_values, + ®db_store_values }, +{ KEY_FORMS, + &key_forms_fetch_keys, + NULL, + &key_forms_fetch_values, + NULL }, +{ KEY_CONTROL_PRINTERS, + &key_printers_fetch_keys, + &key_printers_store_keys, + &key_printers_fetch_values, + &key_printers_store_values }, +{ KEY_ENVIRONMENTS, + &key_driver_fetch_keys, + NULL, + &key_driver_fetch_values, + NULL }, +{ KEY_CONTROL_PRINT, + &key_print_fetch_keys, + NULL, + NULL, + NULL }, +{ KEY_WINNT_PRINTERS, + &key_printers_fetch_keys, + &key_printers_store_keys, + &key_printers_fetch_values, + &key_printers_store_values }, +{ KEY_PORTS, + ®db_fetch_keys, + ®db_store_keys, + ®db_fetch_values, + ®db_store_values }, + +{ NULL, NULL, NULL, NULL, NULL } +}; + + +/********************************************************************** + ********************************************************************* + ** Main reg_printing interface functions + ********************************************************************* + *********************************************************************/ + +/*********************************************************************** + Lookup a key in the print_registry table, returning its index. + -1 on failure + **********************************************************************/ + +static int match_registry_path(const char *key) +{ + int i; + char *path = NULL; + TALLOC_CTX *ctx = talloc_tos(); + + if ( !key ) + return -1; + + path = talloc_strdup(ctx, key); + if (!path) { + return -1; + } + path = normalize_reg_path(ctx, path); + if (!path) { + return -1; + } + + for ( i=0; print_registry[i].path; i++ ) { + if (strncmp( path, print_registry[i].path, strlen(print_registry[i].path) ) == 0 ) + return i; + } + + return -1; +} + +/*********************************************************************** + **********************************************************************/ + +static int regprint_fetch_reg_keys( const char *key, REGSUBKEY_CTR *subkeys ) +{ + int i = match_registry_path( key ); + + if ( i == -1 ) + return -1; + + if ( !print_registry[i].fetch_subkeys ) + return -1; + + return print_registry[i].fetch_subkeys( key, subkeys ); +} + +/********************************************************************** + *********************************************************************/ + +static bool regprint_store_reg_keys( const char *key, REGSUBKEY_CTR *subkeys ) +{ + int i = match_registry_path( key ); + + if ( i == -1 ) + return False; + + if ( !print_registry[i].store_subkeys ) + return False; + + return print_registry[i].store_subkeys( key, subkeys ); +} + +/********************************************************************** + *********************************************************************/ + +static int regprint_fetch_reg_values( const char *key, REGVAL_CTR *values ) +{ + int i = match_registry_path( key ); + + if ( i == -1 ) + return -1; + + /* return 0 values by default since we know the key had + to exist because the client opened a handle */ + + if ( !print_registry[i].fetch_values ) + return 0; + + return print_registry[i].fetch_values( key, values ); +} + +/********************************************************************** + *********************************************************************/ + +static bool regprint_store_reg_values( const char *key, REGVAL_CTR *values ) +{ + int i = match_registry_path( key ); + + if ( i == -1 ) + return False; + + if ( !print_registry[i].store_values ) + return False; + + return print_registry[i].store_values( key, values ); +} + +/* + * Table of function pointers for accessing printing data + */ + +REGISTRY_OPS printing_ops = { + .fetch_subkeys = regprint_fetch_reg_keys, + .fetch_values = regprint_fetch_reg_values, + .store_subkeys = regprint_store_reg_keys, + .store_values = regprint_store_reg_values, +}; |