1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00
samba-mirror/source3/registry/reg_printing.c
Jeremy Allison acf9d61421 r4088: Get medieval on our ass about malloc.... :-). Take control of all our allocation
functions so we can funnel through some well known functions. Should help greatly with
malloc checking.
HEAD patch to follow.
Jeremy.
(This used to be commit 620f2e608f)
2007-10-10 10:53:32 -05:00

829 lines
23 KiB
C

/*
* Unix SMB/CIFS implementation.
* RPC Pipe client / server routines
* Copyright (C) Gerald Carter 2002.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Implementation of registry virtual views for printing information */
#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
#define MAX_TOP_LEVEL_KEYS 3
/* some symbolic indexes into the top_level_keys */
#define KEY_INDEX_ENVIR 0
#define KEY_INDEX_FORMS 1
#define KEY_INDEX_PRINTER 2
static const char *top_level_keys[MAX_TOP_LEVEL_KEYS] = {
"Environments",
"Forms",
"Printers"
};
/**********************************************************************
It is safe to assume that every registry path passed into on of
the exported functions here begins with KEY_PRINTING else
these functions would have never been called. This is a small utility
function to strip the beginning of the path and make a copy that the
caller can modify. Note that the caller is responsible for releasing
the memory allocated here.
**********************************************************************/
static char* trim_reg_path( char *path )
{
char *p;
uint16 key_len = strlen(KEY_PRINTING);
/*
* sanity check...this really should never be True.
* It is only here to prevent us from accessing outside
* the path buffer in the extreme case.
*/
if ( strlen(path) < key_len ) {
DEBUG(0,("trim_reg_path: Registry path too short! [%s]\n", path));
DEBUG(0,("trim_reg_path: KEY_PRINTING => [%s]!\n", KEY_PRINTING));
return NULL;
}
p = path + strlen( KEY_PRINTING );
if ( *p == '\\' )
p++;
if ( *p )
return SMB_STRDUP(p);
else
return NULL;
}
/**********************************************************************
handle enumeration of subkeys below KEY_PRINTING\Environments
*********************************************************************/
static int print_subpath_environments( 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;
BOOL valid_env = False;
char *base, *new_path;
char *keystr;
char *key2 = NULL;
int num_subkeys = -1;
DEBUG(10,("print_subpath_environments: key=>[%s]\n", key ? key : "NULL" ));
/* listed architectures of installed drivers */
if ( !key )
{
/* Windows 9x drivers */
if ( get_ntdrivers( &drivers, environments[0], 0 ) )
regsubkey_ctr_addkey( subkeys, environments[0] );
SAFE_FREE( drivers );
/* Windows NT/2k intel drivers */
if ( get_ntdrivers( &drivers, environments[1], 2 )
|| get_ntdrivers( &drivers, environments[1], 3 ) )
{
regsubkey_ctr_addkey( subkeys, environments[1] );
}
SAFE_FREE( drivers );
/* Windows NT 4.0; non-intel drivers */
for ( i=2; environments[i]; i++ ) {
if ( get_ntdrivers( &drivers, environments[i], 2 ) )
regsubkey_ctr_addkey( subkeys, environments[i] );
}
SAFE_FREE( drivers );
num_subkeys = regsubkey_ctr_numkeys( subkeys );
goto done;
}
/* we are dealing with a subkey of "Environments */
key2 = SMB_STRDUP( key );
keystr = key2;
reg_split_path( keystr, &base, &new_path );
/* sanity check */
for ( env_index=0; environments[env_index]; env_index++ ) {
if ( StrCaseCmp( environments[env_index], base ) == 0 ) {
valid_env = True;
break;
}
}
if ( !valid_env )
return -1;
/* enumerate driver versions; environment is environments[env_index] */
if ( !new_path ) {
switch ( env_index ) {
case 0: /* Win9x */
if ( get_ntdrivers( &drivers, environments[0], 0 ) ) {
regsubkey_ctr_addkey( subkeys, "0" );
SAFE_FREE( drivers );
}
break;
case 1: /* Windows NT/2k - intel */
if ( get_ntdrivers( &drivers, environments[1], 2 ) ) {
regsubkey_ctr_addkey( subkeys, "2" );
SAFE_FREE( drivers );
}
if ( get_ntdrivers( &drivers, environments[1], 3 ) ) {
regsubkey_ctr_addkey( subkeys, "3" );
SAFE_FREE( drivers );
}
break;
default: /* Windows NT - nonintel */
if ( get_ntdrivers( &drivers, environments[env_index], 2 ) ) {
regsubkey_ctr_addkey( subkeys, "2" );
SAFE_FREE( drivers );
}
}
num_subkeys = regsubkey_ctr_numkeys( subkeys );
goto done;
}
/* we finally get to enumerate the drivers */
keystr = new_path;
reg_split_path( keystr, &base, &new_path );
if ( !new_path ) {
num_drivers = get_ntdrivers( &drivers, environments[env_index], atoi(base) );
for ( i=0; i<num_drivers; i++ )
regsubkey_ctr_addkey( subkeys, drivers[i] );
num_subkeys = regsubkey_ctr_numkeys( subkeys );
goto done;
}
done:
SAFE_FREE( key2 );
return num_subkeys;
}
/***********************************************************************
simple function to prune a pathname down to the basename of a file
**********************************************************************/
static char* dos_basename ( char *path )
{
char *p;
p = strrchr( path, '\\' );
if ( p )
p++;
else
p = path;
return p;
}
/**********************************************************************
handle enumeration of values below
KEY_PRINTING\Environments\<arch>\<version>\<drivername>
*********************************************************************/
static int print_subpath_values_environments( char *key, REGVAL_CTR *val )
{
char *keystr;
char *key2 = NULL;
char *base, *new_path;
fstring env;
fstring driver;
int version;
NT_PRINTER_DRIVER_INFO_LEVEL driver_ctr;
NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
WERROR w_result;
char *buffer = NULL;
char *buffer2 = NULL;
int buffer_size = 0;
int i, length;
char *filename;
UNISTR2 data;;
DEBUG(8,("print_subpath_values_environments: Enter key => [%s]\n", key ? key : "NULL"));
if ( !key )
return 0;
/*
* The only key below KEY_PRINTING\Environments that
* posseses values is each specific printer driver
* First get the arch, version, & driver name
*/
/* env */
key2 = SMB_STRDUP( key );
keystr = key2;
reg_split_path( keystr, &base, &new_path );
if ( !base || !new_path )
return 0;
fstrcpy( env, base );
/* version */
keystr = new_path;
reg_split_path( keystr, &base, &new_path );
if ( !base || !new_path )
return 0;
version = atoi( base );
/* printer driver name */
keystr = new_path;
reg_split_path( keystr, &base, &new_path );
/* new_path should be NULL here since this must be the last key */
if ( !base || new_path )
return 0;
fstrcpy( driver, base );
w_result = get_a_printer_driver( &driver_ctr, 3, driver, env, version );
if ( !W_ERROR_IS_OK(w_result) )
return -1;
/* build the values out of the driver information */
info3 = driver_ctr.info_3;
filename = dos_basename( info3->driverpath );
init_unistr2( &data, filename, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "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( val, "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( val, "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( val, "Help File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info3->defaultdatatype, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Data Type", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
regval_ctr_addvalue( val, "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);
buffer2 = SMB_REALLOC( buffer, buffer_size + (length + 1)*sizeof(uint16) );
if ( !buffer2 )
break;
buffer = buffer2;
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 */
buffer2 = SMB_REALLOC( buffer, buffer_size + 2 );
if ( !buffer2 ) {
SAFE_FREE( buffer );
buffer_size = 0;
} else {
buffer = buffer2;
buffer[buffer_size++] = '\0';
buffer[buffer_size++] = '\0';
}
}
regval_ctr_addvalue( val, "Dependent Files", REG_MULTI_SZ, buffer, buffer_size );
free_a_printer_driver( driver_ctr, 3 );
SAFE_FREE( key2 );
SAFE_FREE( buffer );
DEBUG(8,("print_subpath_values_environments: Exit\n"));
return regval_ctr_numvals( val );
}
/**********************************************************************
handle enumeration of subkeys below KEY_PRINTING\Forms
Really just a stub function, but left here in case it needs to
be expanded later on
*********************************************************************/
static int print_subpath_forms( char *key, REGSUBKEY_CTR *subkeys )
{
DEBUG(10,("print_subpath_forms: key=>[%s]\n", key ? key : "NULL" ));
/* there are no subkeys */
if ( key )
return -1;
return 0;
}
/**********************************************************************
handle enumeration of values below KEY_PRINTING\Forms
*********************************************************************/
static int print_subpath_values_forms( char *key, REGVAL_CTR *val )
{
int num_values = 0;
uint32 data[8];
int form_index = 1;
DEBUG(10,("print_values_forms: key=>[%s]\n", key ? key : "NULL" ));
/* handle ..\Forms\ */
if ( !key )
{
nt_forms_struct *forms_list = NULL;
nt_forms_struct *form = NULL;
int i;
if ( (num_values = get_ntforms( &forms_list )) == 0 )
return 0;
DEBUG(10,("print_subpath_values_forms: [%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( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
}
SAFE_FREE( forms_list );
forms_list = NULL;
/* handle built-on forms */
if ( (num_values = get_builtin_ntforms( &forms_list )) == 0 )
return 0;
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( val, form->name, REG_BINARY, (char*)data, sizeof(data) );
}
SAFE_FREE( forms_list );
}
return num_values;
}
/**********************************************************************
handle enumeration of subkeys below KEY_PRINTING\Printers
*********************************************************************/
static int print_subpath_printers( char *key, REGSUBKEY_CTR *subkeys )
{
int n_services = lp_numservices();
int snum;
fstring sname;
int i;
int num_subkeys = 0;
char *keystr, *key2 = NULL;
char *base, *new_path;
NT_PRINTER_INFO_LEVEL *printer = NULL;
fstring *subkey_names = NULL;
DEBUG(10,("print_subpath_printers: key=>[%s]\n", key ? key : "NULL" ));
if ( !key )
{
/* enumerate all printers */
for (snum=0; snum<n_services; snum++) {
if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
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 */
key2 = SMB_STRDUP( key );
keystr = key2;
reg_split_path( keystr, &base, &new_path );
if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, base) ) )
goto done;
num_subkeys = get_printer_subkeys( &printer->info_2->data, new_path?new_path:"", &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( key2 );
SAFE_FREE( subkey_names );
return num_subkeys;
}
/**********************************************************************
handle enumeration of values below KEY_PRINTING\Printers
*********************************************************************/
static int print_subpath_values_printers( char *key, REGVAL_CTR *val )
{
int num_values = 0;
char *keystr, *key2 = NULL;
char *base, *new_path;
NT_PRINTER_INFO_LEVEL *printer = NULL;
NT_PRINTER_INFO_LEVEL_2 *info2;
DEVICEMODE *devmode;
prs_struct prs;
uint32 offset;
int snum;
fstring printername;
NT_PRINTER_DATA *p_data;
int i, key_index;
UNISTR2 data;
/*
* Theres are tw cases to deal with here
* (1) enumeration of printer_info_2 values
* (2) enumeration of the PrinterDriverData subney
*/
if ( !key ) {
/* top level key has no values */
goto done;
}
key2 = SMB_STRDUP( key );
keystr = key2;
reg_split_path( keystr, &base, &new_path );
fstrcpy( printername, base );
if ( !new_path )
{
/* we are dealing with the printer itself */
if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
goto done;
info2 = printer->info_2;
regval_ctr_addvalue( val, "Attributes", REG_DWORD, (char*)&info2->attributes, sizeof(info2->attributes) );
regval_ctr_addvalue( val, "Priority", REG_DWORD, (char*)&info2->priority, sizeof(info2->attributes) );
regval_ctr_addvalue( val, "ChangeID", REG_DWORD, (char*)&info2->changeid, sizeof(info2->changeid) );
regval_ctr_addvalue( val, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) );
regval_ctr_addvalue( val, "Status", REG_DWORD, (char*)&info2->status, sizeof(info2->status) );
regval_ctr_addvalue( val, "StartTime", REG_DWORD, (char*)&info2->starttime, sizeof(info2->starttime) );
regval_ctr_addvalue( val, "UntilTime", REG_DWORD, (char*)&info2->untiltime, sizeof(info2->untiltime) );
regval_ctr_addvalue( val, "cjobs", REG_DWORD, (char*)&info2->cjobs, sizeof(info2->cjobs) );
regval_ctr_addvalue( val, "AveragePPM", REG_DWORD, (char*)&info2->averageppm, sizeof(info2->averageppm) );
init_unistr2( &data, info2->printername, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info2->location, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info2->comment, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Comment", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info2->portname, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info2->servername, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Server", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Share", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
init_unistr2( &data, "winprint", UNI_STR_TERMINATE);
regval_ctr_addvalue( val, "Print Processor", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
/* use a prs_struct for converting the devmode and security
descriptor to REG_BIARY */
prs_init( &prs, MAX_PDU_FRAG_LEN, regval_ctr_getctx(val), MARSHALL);
/* stream the device mode */
snum = lp_servicenumber(info2->sharename);
if ( (devmode = construct_dev_mode( snum )) != NULL )
{
if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) {
offset = prs_offset( &prs );
regval_ctr_addvalue( val, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset );
}
}
prs_mem_clear( &prs );
prs_set_offset( &prs, 0 );
if ( info2->secdesc_buf && info2->secdesc_buf->len )
{
if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) {
offset = prs_offset( &prs );
regval_ctr_addvalue( val, "Security", REG_BINARY, prs_data_p(&prs), offset );
}
}
prs_mem_free( &prs );
num_values = regval_ctr_numvals( val );
goto done;
}
/* now enumerate the key */
if ( !W_ERROR_IS_OK( get_a_printer(NULL, &printer, 2, printername) ) )
goto done;
/* iterate over all printer data and fill the regval container */
p_data = &printer->info_2->data;
if ( (key_index = lookup_printerkey( p_data, new_path )) == -1 ) {
DEBUG(10,("print_subpath_values_printer: Unknown keyname [%s]\n", new_path));
goto done;
}
num_values = regval_ctr_numvals( &p_data->keys[key_index].values );
for ( i=0; i<num_values; i++ )
regval_ctr_copyvalue( val, regval_ctr_specific_value(&p_data->keys[key_index].values, i) );
done:
if ( printer )
free_a_printer( &printer, 2 );
SAFE_FREE( key2 );
return num_values;
}
/**********************************************************************
Routine to handle enumeration of subkeys and values
below KEY_PRINTING (depending on whether or not subkeys/val are
valid pointers.
*********************************************************************/
static int handle_printing_subpath( char *key, REGSUBKEY_CTR *subkeys, REGVAL_CTR *val )
{
int result = 0;
char *p, *base;
int i;
DEBUG(10,("handle_printing_subpath: key=>[%s]\n", key ));
/*
* break off the first part of the path
* topmost base **must** be one of the strings
* in top_level_keys[]
*/
reg_split_path( key, &base, &p);
for ( i=0; i<MAX_TOP_LEVEL_KEYS; i++ ) {
if ( StrCaseCmp( top_level_keys[i], base ) == 0 )
break;
}
DEBUG(10,("handle_printing_subpath: base=>[%s], i==[%d]\n", base, i));
if ( !(i < MAX_TOP_LEVEL_KEYS) )
return -1;
/* Call routine to handle each top level key */
switch ( i )
{
case KEY_INDEX_ENVIR:
if ( subkeys )
print_subpath_environments( p, subkeys );
if ( val )
print_subpath_values_environments( p, val );
break;
case KEY_INDEX_FORMS:
if ( subkeys )
print_subpath_forms( p, subkeys );
if ( val )
print_subpath_values_forms( p, val );
break;
case KEY_INDEX_PRINTER:
if ( subkeys )
print_subpath_printers( p, subkeys );
if ( val )
print_subpath_values_printers( p, val );
break;
/* default case for top level key that has no handler */
default:
break;
}
return result;
}
/**********************************************************************
Enumerate registry subkey names given a registry path.
Caller is responsible for freeing memory to **subkeys
*********************************************************************/
int printing_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr )
{
char *path;
BOOL top_level = False;
int num_subkeys = 0;
DEBUG(10,("printing_subkey_info: key=>[%s]\n", key));
path = trim_reg_path( key );
/* check to see if we are dealing with the top level key */
if ( !path )
top_level = True;
if ( top_level ) {
for ( num_subkeys=0; num_subkeys<MAX_TOP_LEVEL_KEYS; num_subkeys++ )
regsubkey_ctr_addkey( subkey_ctr, top_level_keys[num_subkeys] );
}
else
num_subkeys = handle_printing_subpath( path, subkey_ctr, NULL );
SAFE_FREE( path );
return num_subkeys;
}
/**********************************************************************
Enumerate registry values given a registry path.
Caller is responsible for freeing memory
*********************************************************************/
int printing_value_info( char *key, REGVAL_CTR *val )
{
char *path;
BOOL top_level = False;
int num_values = 0;
DEBUG(10,("printing_value_info: key=>[%s]\n", key));
path = trim_reg_path( key );
/* check to see if we are dealing with the top level key */
if ( !path )
top_level = True;
/* fill in values from the getprinterdata_printer_server() */
if ( top_level )
num_values = 0;
else
num_values = handle_printing_subpath( path, NULL, val );
return num_values;
}
/**********************************************************************
Stub function which always returns failure since we don't want
people storing printing information directly via regostry calls
(for now at least)
*********************************************************************/
BOOL printing_store_subkey( char *key, REGSUBKEY_CTR *subkeys )
{
return False;
}
/**********************************************************************
Stub function which always returns failure since we don't want
people storing printing information directly via regostry calls
(for now at least)
*********************************************************************/
BOOL printing_store_value( char *key, REGVAL_CTR *val )
{
return False;
}
/*
* Table of function pointers for accessing printing data
*/
REGISTRY_OPS printing_ops = {
printing_subkey_info,
printing_value_info,
printing_store_subkey,
printing_store_value
};