summaryrefslogtreecommitdiff
path: root/source4/registry
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-08-13 01:53:07 +0000
committerAndrew Tridgell <tridge@samba.org>2003-08-13 01:53:07 +0000
commitef2e26c91b80556af033d3335e55f5dfa6fff31d (patch)
treefaa21bfd7e7b5247250b47c7891dc1a5ebee6be9 /source4/registry
downloadsamba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.tar.gz
samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.tar.bz2
samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.zip
first public release of samba4 code
(This used to be commit b0510b5428b3461aeb9bbe3cc95f62fc73e2b97f)
Diffstat (limited to 'source4/registry')
-rw-r--r--source4/registry/reg_cachehook.c112
-rw-r--r--source4/registry/reg_db.c311
-rw-r--r--source4/registry/reg_frontend.c260
-rw-r--r--source4/registry/reg_objects.c374
-rw-r--r--source4/registry/reg_printing.c829
5 files changed, 1886 insertions, 0 deletions
diff --git a/source4/registry/reg_cachehook.c b/source4/registry/reg_cachehook.c
new file mode 100644
index 0000000000..547eed392d
--- /dev/null
+++ b/source4/registry/reg_cachehook.c
@@ -0,0 +1,112 @@
+/*
+ * 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 hook cache tree */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+static SORTED_TREE *cache_tree;
+extern REGISTRY_OPS regdb_ops; /* these are the default */
+static REGISTRY_HOOK default_hook = { KEY_TREE_ROOT, &regdb_ops };
+
+/**********************************************************************
+ Initialize the cache tree
+ *********************************************************************/
+
+BOOL reghook_cache_init( void )
+{
+ cache_tree = sorted_tree_init( &default_hook, NULL, NULL );
+
+ return ( cache_tree == NULL );
+}
+
+/**********************************************************************
+ Add a new REGISTRY_HOOK to the cache. Note that the keyname
+ is not in the exact format that a SORTED_TREE expects.
+ *********************************************************************/
+
+BOOL reghook_cache_add( REGISTRY_HOOK *hook )
+{
+ pstring key;
+
+ if ( !hook )
+ return False;
+
+ pstrcpy( key, "\\");
+ pstrcat( key, hook->keyname );
+
+ pstring_sub( key, "\\", "/" );
+
+ DEBUG(10,("reghook_cache_add: Adding key [%s]\n", key));
+
+ return sorted_tree_add( cache_tree, key, hook );
+}
+
+/**********************************************************************
+ Initialize the cache tree
+ *********************************************************************/
+
+REGISTRY_HOOK* reghook_cache_find( char *keyname )
+{
+ char *key;
+ int len;
+ REGISTRY_HOOK *hook;
+
+ if ( !keyname )
+ return NULL;
+
+ /* prepend the string with a '\' character */
+
+ len = strlen( keyname );
+ if ( !(key = malloc( len + 2 )) ) {
+ DEBUG(0,("reghook_cache_find: malloc failed for string [%s] !?!?!\n",
+ keyname));
+ return NULL;
+ }
+
+ *key = '\\';
+ strncpy( key+1, keyname, len+1);
+
+ /* swap to a form understood by the SORTED_TREE */
+
+ string_sub( key, "\\", "/", 0 );
+
+ DEBUG(10,("reghook_cache_find: Searching for keyname [%s]\n", key));
+
+ hook = sorted_tree_find( cache_tree, key ) ;
+
+ SAFE_FREE( key );
+
+ return hook;
+}
+
+/**********************************************************************
+ Initialize the cache tree
+ *********************************************************************/
+
+void reghook_dump_cache( int debuglevel )
+{
+ DEBUG(debuglevel,("reghook_dump_cache: Starting cache dump now...\n"));
+
+ sorted_tree_print_keys( cache_tree, debuglevel );
+}
diff --git a/source4/registry/reg_db.c b/source4/registry/reg_db.c
new file mode 100644
index 0000000000..b0917c8f60
--- /dev/null
+++ b/source4/registry/reg_db.c
@@ -0,0 +1,311 @@
+/*
+ * 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 internal registry database functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+static TDB_CONTEXT *tdb_reg;
+
+
+/***********************************************************************
+ Open the registry data in the tdb
+ ***********************************************************************/
+
+static BOOL init_registry_data( void )
+{
+ pstring keyname;
+ REGSUBKEY_CTR subkeys;
+
+ ZERO_STRUCTP( &subkeys );
+
+ /* HKEY_LOCAL_MACHINE */
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ regsubkey_ctr_addkey( &subkeys, "SYSTEM" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM" );
+ regsubkey_ctr_addkey( &subkeys, "CurrentControlSet" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet" );
+ regsubkey_ctr_addkey( &subkeys, "Control" );
+ regsubkey_ctr_addkey( &subkeys, "Services" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control" );
+ regsubkey_ctr_addkey( &subkeys, "Print" );
+ regsubkey_ctr_addkey( &subkeys, "ProductOptions" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control/ProductOptions" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services" );
+ regsubkey_ctr_addkey( &subkeys, "Netlogon" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ regsubkey_ctr_init( &subkeys );
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Netlogon" );
+ regsubkey_ctr_addkey( &subkeys, "Parameters" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+ regsubkey_ctr_destroy( &subkeys );
+
+ pstrcpy( keyname, KEY_HKLM );
+ pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Netlogon/Parameters" );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ))
+ return False;
+
+ /* HKEY_USER */
+
+ pstrcpy( keyname, KEY_HKU );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ) )
+ return False;
+
+ /* HKEY_CLASSES_ROOT*/
+
+ pstrcpy( keyname, KEY_HKCR );
+ if ( !regdb_store_reg_keys( keyname, &subkeys ) )
+ return False;
+
+ return True;
+}
+
+/***********************************************************************
+ Open the registry database
+ ***********************************************************************/
+
+BOOL init_registry_db( void )
+{
+ static pid_t local_pid;
+
+ if (tdb_reg && local_pid == sys_getpid())
+ return True;
+
+ /*
+ * try to open first without creating so we can determine
+ * if we need to init the data in the registry
+ */
+
+ tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
+ if ( !tdb_reg )
+ {
+ tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ if ( !tdb_reg ) {
+ DEBUG(0,("init_registry: Failed to open registry %s (%s)\n",
+ lock_path("registry.tdb"), strerror(errno) ));
+ return False;
+ }
+
+ DEBUG(10,("init_registry: Successfully created registry tdb\n"));
+
+ /* create the registry here */
+ if ( !init_registry_data() ) {
+ DEBUG(0,("init_registry: Failed to initiailize data in registry!\n"));
+ return False;
+ }
+ }
+
+ local_pid = sys_getpid();
+
+ return True;
+}
+
+
+
+/***********************************************************************
+ Add subkey strings to the registry tdb under a defined key
+ fmt is the same format as tdb_pack except this function only supports
+ fstrings
+
+ The full path to the registry key is used as database after the
+ \'s are converted to /'s. Key string is also normalized to UPPER
+ case.
+ ***********************************************************************/
+
+BOOL regdb_store_reg_keys( char *keyname, REGSUBKEY_CTR *ctr )
+{
+ TDB_DATA kbuf, dbuf;
+ char *buffer, *tmpbuf;
+ int i = 0;
+ uint32 len, buflen;
+ BOOL ret = True;
+ uint32 num_subkeys = regsubkey_ctr_numkeys( ctr );
+
+ if ( !keyname )
+ return False;
+
+ strupper_m( keyname );
+
+ /* allocate some initial memory */
+
+ buffer = malloc(sizeof(pstring));
+ buflen = sizeof(pstring);
+ len = 0;
+
+ /* store the number of subkeys */
+
+ len += tdb_pack(buffer+len, buflen-len, "d", num_subkeys );
+
+ /* pack all the strings */
+
+ for (i=0; i<num_subkeys; i++) {
+ len += tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
+ if ( len > buflen ) {
+ /* allocate some extra space */
+ if ((tmpbuf = Realloc( buffer, len*2 )) == NULL) {
+ DEBUG(0,("regdb_store_reg_keys: Failed to realloc memory of size [%d]\n", len*2));
+ ret = False;
+ goto done;
+ }
+ buffer = tmpbuf;
+ buflen = len*2;
+
+ len = tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
+ }
+ }
+
+ /* finally write out the data */
+
+ kbuf.dptr = keyname;
+ kbuf.dsize = strlen(keyname)+1;
+ dbuf.dptr = buffer;
+ dbuf.dsize = len;
+ if ( tdb_store( tdb_reg, kbuf, dbuf, TDB_REPLACE ) == -1) {
+ ret = False;
+ goto done;
+ }
+
+done:
+ SAFE_FREE( buffer );
+
+ return ret;
+}
+
+/***********************************************************************
+ Retrieve an array of strings containing subkeys. Memory should be
+ released by the caller. The subkeys are stored in a catenated string
+ of null terminated character strings
+ ***********************************************************************/
+
+int regdb_fetch_reg_keys( char* key, REGSUBKEY_CTR *ctr )
+{
+ pstring path;
+ uint32 num_items;
+ TDB_DATA dbuf;
+ char *buf;
+ uint32 buflen, len;
+ int i;
+ fstring subkeyname;
+
+ DEBUG(10,("regdb_fetch_reg_keys: Enter key => [%s]\n", key ? key : "NULL"));
+
+ pstrcpy( path, key );
+
+ /* convert to key format */
+ pstring_sub( path, "\\", "/" );
+ strupper_m( path );
+
+ dbuf = tdb_fetch_by_string( tdb_reg, path );
+
+ buf = dbuf.dptr;
+ buflen = dbuf.dsize;
+
+ if ( !buf ) {
+ DEBUG(5,("regdb_fetch_reg_keys: tdb lookup failed to locate key [%s]\n", key));
+ return -1;
+ }
+
+ len = tdb_unpack( buf, buflen, "d", &num_items);
+
+ for (i=0; i<num_items; i++) {
+ len += tdb_unpack( buf+len, buflen-len, "f", subkeyname );
+ regsubkey_ctr_addkey( ctr, subkeyname );
+ }
+
+ SAFE_FREE( dbuf.dptr );
+
+ DEBUG(10,("regdb_fetch_reg_keys: Exit [%d] items\n", num_items));
+
+ return num_items;
+}
+
+
+/***********************************************************************
+ Retrieve an array of strings containing subkeys. Memory should be
+ released by the caller. The subkeys are stored in a catenated string
+ of null terminated character strings
+ ***********************************************************************/
+
+int regdb_fetch_reg_values( char* key, REGVAL_CTR *val )
+{
+ return 0;
+}
+
+/***********************************************************************
+ Stub function since we do not currently support storing registry
+ values in the registry.tdb
+ ***********************************************************************/
+
+BOOL regdb_store_reg_values( char *key, REGVAL_CTR *val )
+{
+ return False;
+}
+
+
+/*
+ * Table of function pointers for default access
+ */
+
+REGISTRY_OPS regdb_ops = {
+ regdb_fetch_reg_keys,
+ regdb_fetch_reg_values,
+ regdb_store_reg_keys,
+ regdb_store_reg_values
+};
+
+
diff --git a/source4/registry/reg_frontend.c b/source4/registry/reg_frontend.c
new file mode 100644
index 0000000000..a9dfb52f01
--- /dev/null
+++ b/source4/registry/reg_frontend.c
@@ -0,0 +1,260 @@
+/*
+ * 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 frontend view functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+extern REGISTRY_OPS printing_ops;
+extern REGISTRY_OPS regdb_ops; /* these are the default */
+
+/* array of REGISTRY_HOOK's which are read into a tree for easy access */
+
+
+REGISTRY_HOOK reg_hooks[] = {
+ { KEY_PRINTING, &printing_ops },
+ { NULL, NULL }
+};
+
+
+/***********************************************************************
+ Open the registry database and initialize the REGISTRY_HOOK cache
+ ***********************************************************************/
+
+BOOL init_registry( void )
+{
+ int i;
+
+ if ( !init_registry_db() ) {
+ DEBUG(0,("init_registry: failed to initialize the registry tdb!\n"));
+ return False;
+ }
+
+ /* build the cache tree of registry hooks */
+
+ reghook_cache_init();
+
+ for ( i=0; reg_hooks[i].keyname; i++ ) {
+ if ( !reghook_cache_add(&reg_hooks[i]) )
+ return False;
+ }
+
+ if ( DEBUGLEVEL >= 20 )
+ reghook_dump_cache(20);
+
+ return True;
+}
+
+
+
+
+/***********************************************************************
+ High level wrapper function for storing registry subkeys
+ ***********************************************************************/
+
+BOOL store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys )
+{
+ if ( key->hook && key->hook->ops && key->hook->ops->store_subkeys_fn )
+ return key->hook->ops->store_subkeys_fn( key->name, subkeys );
+ else
+ return False;
+
+}
+
+/***********************************************************************
+ High level wrapper function for storing registry values
+ ***********************************************************************/
+
+BOOL store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
+{
+ if ( key->hook && key->hook->ops && key->hook->ops->store_values_fn )
+ return key->hook->ops->store_values_fn( key->name, val );
+ else
+ return False;
+}
+
+
+/***********************************************************************
+ High level wrapper function for enumerating registry subkeys
+ Initialize the TALLOC_CTX if necessary
+ ***********************************************************************/
+
+int fetch_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkey_ctr )
+{
+ int result = -1;
+
+ if ( key->hook && key->hook->ops && key->hook->ops->subkey_fn )
+ result = key->hook->ops->subkey_fn( key->name, subkey_ctr );
+
+ return result;
+}
+
+/***********************************************************************
+ retreive a specific subkey specified by index. Caller is
+ responsible for freeing memory
+ ***********************************************************************/
+
+BOOL fetch_reg_keys_specific( REGISTRY_KEY *key, char** subkey, uint32 key_index )
+{
+ static REGSUBKEY_CTR ctr;
+ static pstring save_path;
+ static BOOL ctr_init = False;
+ char *s;
+
+ *subkey = NULL;
+
+ /* simple caching for performance; very basic heuristic */
+
+ if ( !ctr_init ) {
+ DEBUG(8,("fetch_reg_keys_specific: Initializing cache of subkeys for [%s]\n", key->name));
+ ZERO_STRUCTP( &ctr );
+ regsubkey_ctr_init( &ctr );
+
+ pstrcpy( save_path, key->name );
+
+ if ( fetch_reg_keys( key, &ctr) == -1 )
+ return False;
+
+ ctr_init = True;
+ }
+ /* clear the cache when key_index == 0 or the path has changed */
+ else if ( !key_index || StrCaseCmp( save_path, key->name) ) {
+
+ DEBUG(8,("fetch_reg_keys_specific: Updating cache of subkeys for [%s]\n", key->name));
+
+ regsubkey_ctr_destroy( &ctr );
+ regsubkey_ctr_init( &ctr );
+
+ pstrcpy( save_path, key->name );
+
+ if ( fetch_reg_keys( key, &ctr) == -1 )
+ return False;
+ }
+
+ if ( !(s = regsubkey_ctr_specific_key( &ctr, key_index )) )
+ return False;
+
+ *subkey = strdup( s );
+
+ return True;
+}
+
+
+/***********************************************************************
+ High level wrapper function for enumerating registry values
+ Initialize the TALLOC_CTX if necessary
+ ***********************************************************************/
+
+int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
+{
+ int result = -1;
+
+ if ( key->hook && key->hook->ops && key->hook->ops->value_fn )
+ result = key->hook->ops->value_fn( key->name, val );
+
+ return result;
+}
+
+
+/***********************************************************************
+ retreive a specific subkey specified by index. Caller is
+ responsible for freeing memory
+ ***********************************************************************/
+
+BOOL fetch_reg_values_specific( REGISTRY_KEY *key, REGISTRY_VALUE **val, uint32 val_index )
+{
+ static REGVAL_CTR ctr;
+ static pstring save_path;
+ static BOOL ctr_init = False;
+ REGISTRY_VALUE *v;
+
+ *val = NULL;
+
+ /* simple caching for performance; very basic heuristic */
+
+ if ( !ctr_init ) {
+ DEBUG(8,("fetch_reg_values_specific: Initializing cache of values for [%s]\n", key->name));
+
+ ZERO_STRUCTP( &ctr );
+ regval_ctr_init( &ctr );
+
+ pstrcpy( save_path, key->name );
+
+ if ( fetch_reg_values( key, &ctr) == -1 )
+ return False;
+
+ ctr_init = True;
+ }
+ /* clear the cache when val_index == 0 or the path has changed */
+ else if ( !val_index || StrCaseCmp(save_path, key->name) ) {
+
+ DEBUG(8,("fetch_reg_values_specific: Updating cache of values for [%s]\n", key->name));
+
+ regval_ctr_destroy( &ctr );
+ regval_ctr_init( &ctr );
+
+ pstrcpy( save_path, key->name );
+
+ if ( fetch_reg_values( key, &ctr) == -1 )
+ return False;
+ }
+
+ if ( !(v = regval_ctr_specific_value( &ctr, val_index )) )
+ return False;
+
+ *val = dup_registry_value( v );
+
+ return True;
+}
+
+/***********************************************************************
+ Utility function for splitting the base path of a registry path off
+ by setting base and new_path to the apprapriate offsets withing the
+ path.
+
+ WARNING!! Does modify the original string!
+ ***********************************************************************/
+
+BOOL reg_split_path( char *path, char **base, char **new_path )
+{
+ char *p;
+
+ *new_path = *base = NULL;
+
+ if ( !path)
+ return False;
+
+ *base = path;
+
+ p = strchr( path, '\\' );
+
+ if ( p ) {
+ *p = '\0';
+ *new_path = p+1;
+ }
+
+ return True;
+}
+
+
+
diff --git a/source4/registry/reg_objects.c b/source4/registry/reg_objects.c
new file mode 100644
index 0000000000..9cfeb7faa9
--- /dev/null
+++ b/source4/registry/reg_objects.c
@@ -0,0 +1,374 @@
+/*
+ * 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 frontend view functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+
+/***********************************************************************
+ Init the talloc context held by a REGSUBKEY_CTR structure
+ **********************************************************************/
+
+void regsubkey_ctr_init( REGSUBKEY_CTR *ctr )
+{
+ if ( !ctr->ctx )
+ ctr->ctx = talloc_init("regsubkey_ctr_init for ctr %p", ctr);
+}
+
+/***********************************************************************
+ Add a new key to the array
+ **********************************************************************/
+
+int regsubkey_ctr_addkey( REGSUBKEY_CTR *ctr, const char *keyname )
+{
+ uint32 len;
+ char **pp;
+
+ if ( keyname )
+ {
+ len = strlen( keyname );
+
+ /* allocate a space for the char* in the array */
+
+ if ( ctr->subkeys == 0 )
+ ctr->subkeys = talloc( ctr->ctx, sizeof(char*) );
+ else {
+ pp = talloc_realloc( ctr->ctx, ctr->subkeys, sizeof(char*)*(ctr->num_subkeys+1) );
+ if ( pp )
+ ctr->subkeys = pp;
+ }
+
+ /* allocate the string and save it in the array */
+
+ ctr->subkeys[ctr->num_subkeys] = talloc( ctr->ctx, len+1 );
+ strncpy( ctr->subkeys[ctr->num_subkeys], keyname, len+1 );
+ ctr->num_subkeys++;
+ }
+
+ return ctr->num_subkeys;
+}
+
+/***********************************************************************
+ How many keys does the container hold ?
+ **********************************************************************/
+
+int regsubkey_ctr_numkeys( REGSUBKEY_CTR *ctr )
+{
+ return ctr->num_subkeys;
+}
+
+/***********************************************************************
+ Retreive a specific key string
+ **********************************************************************/
+
+char* regsubkey_ctr_specific_key( REGSUBKEY_CTR *ctr, uint32 key_index )
+{
+ if ( ! (key_index < ctr->num_subkeys) )
+ return NULL;
+
+ return ctr->subkeys[key_index];
+}
+
+/***********************************************************************
+ free memory held by a REGSUBKEY_CTR structure
+ **********************************************************************/
+
+void regsubkey_ctr_destroy( REGSUBKEY_CTR *ctr )
+{
+ if ( ctr ) {
+ talloc_destroy( ctr->ctx );
+ ZERO_STRUCTP( ctr );
+ }
+}
+
+
+/*
+ * Utility functions for REGVAL_CTR
+ */
+
+/***********************************************************************
+ Init the talloc context held by a REGSUBKEY_CTR structure
+ **********************************************************************/
+
+void regval_ctr_init( REGVAL_CTR *ctr )
+{
+ if ( !ctr->ctx )
+ ctr->ctx = talloc_init("regval_ctr_init for ctr %p", ctr);
+}
+
+/***********************************************************************
+ How many keys does the container hold ?
+ **********************************************************************/
+
+int regval_ctr_numvals( REGVAL_CTR *ctr )
+{
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ allocate memory for and duplicate a REGISTRY_VALUE.
+ This is malloc'd memory so the caller should free it when done
+ **********************************************************************/
+
+REGISTRY_VALUE* dup_registry_value( REGISTRY_VALUE *val )
+{
+ REGISTRY_VALUE *copy = NULL;
+
+ if ( !val )
+ return NULL;
+
+ if ( !(copy = malloc( sizeof(REGISTRY_VALUE) )) ) {
+ DEBUG(0,("dup_registry_value: malloc() failed!\n"));
+ return NULL;
+ }
+
+ /* copy all the non-pointer initial data */
+
+ memcpy( copy, val, sizeof(REGISTRY_VALUE) );
+ if ( val->data_p )
+ {
+ if ( !(copy->data_p = memdup( val->data_p, val->size )) ) {
+ DEBUG(0,("dup_registry_value: memdup() failed for [%d] bytes!\n",
+ val->size));
+ SAFE_FREE( copy );
+ }
+ }
+
+ return copy;
+}
+
+/**********************************************************************
+ free the memory allocated to a REGISTRY_VALUE
+ *********************************************************************/
+
+void free_registry_value( REGISTRY_VALUE *val )
+{
+ if ( !val )
+ return;
+
+ SAFE_FREE( val->data_p );
+ SAFE_FREE( val );
+
+ return;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint8* regval_data_p( REGISTRY_VALUE *val )
+{
+ return val->data_p;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+int regval_size( REGISTRY_VALUE *val )
+{
+ return val->size;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+char* regval_name( REGISTRY_VALUE *val )
+{
+ return val->valuename;
+}
+
+/**********************************************************************
+ *********************************************************************/
+
+uint32 regval_type( REGISTRY_VALUE *val )
+{
+ return val->type;
+}
+
+/***********************************************************************
+ Retreive a pointer to a specific value. Caller shoud dup the structure
+ since this memory may go away with a regval_ctr_destroy()
+ **********************************************************************/
+
+REGISTRY_VALUE* regval_ctr_specific_value( REGVAL_CTR *ctr, uint32 idx )
+{
+ if ( !(idx < ctr->num_values) )
+ return NULL;
+
+ return ctr->values[idx];
+}
+
+/***********************************************************************
+ Retrive the TALLOC_CTX associated with a REGISTRY_VALUE
+ **********************************************************************/
+
+TALLOC_CTX* regval_ctr_getctx( REGVAL_CTR *val )
+{
+ if ( !val )
+ return NULL;
+
+ return val->ctx;
+}
+
+/***********************************************************************
+ Add a new registry value to the array
+ **********************************************************************/
+
+int regval_ctr_addvalue( REGVAL_CTR *ctr, const char *name, uint16 type,
+ const char *data_p, size_t size )
+{
+ REGISTRY_VALUE **ppreg;
+
+ if ( name )
+ {
+ /* allocate a slot in the array of pointers */
+
+ if ( ctr->num_values == 0 )
+ ctr->values = talloc( ctr->ctx, sizeof(REGISTRY_VALUE*) );
+ else {
+ ppreg = talloc_realloc( ctr->ctx, ctr->values, sizeof(REGISTRY_VALUE*)*(ctr->num_values+1) );
+ if ( ppreg )
+ ctr->values = ppreg;
+ }
+
+ /* allocate a new value and store the pointer in the arrya */
+
+ ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
+
+ /* init the value */
+
+ fstrcpy( ctr->values[ctr->num_values]->valuename, name );
+ ctr->values[ctr->num_values]->type = type;
+ ctr->values[ctr->num_values]->data_p = talloc_memdup( ctr->ctx, data_p, size );
+ ctr->values[ctr->num_values]->size = size;
+ ctr->num_values++;
+ }
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Add a new registry value to the array
+ **********************************************************************/
+
+int regval_ctr_copyvalue( REGVAL_CTR *ctr, REGISTRY_VALUE *val )
+{
+ REGISTRY_VALUE **ppreg;
+
+ if ( val )
+ {
+ /* allocate a slot in the array of pointers */
+
+ if ( ctr->num_values == 0 )
+ ctr->values = talloc( ctr->ctx, sizeof(REGISTRY_VALUE*) );
+ else {
+ ppreg = talloc_realloc( ctr->ctx, ctr->values, sizeof(REGISTRY_VALUE*)*(ctr->num_values+1) );
+ if ( ppreg )
+ ctr->values = ppreg;
+ }
+
+ /* allocate a new value and store the pointer in the arrya */
+
+ ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
+
+ /* init the value */
+
+ fstrcpy( ctr->values[ctr->num_values]->valuename, val->valuename );
+ ctr->values[ctr->num_values]->type = val->type;
+ ctr->values[ctr->num_values]->data_p = talloc_memdup( ctr->ctx, val->data_p, val->size );
+ ctr->values[ctr->num_values]->size = val->size;
+ ctr->num_values++;
+ }
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Delete a single value from the registry container.
+ No need to free memory since it is talloc'd.
+ **********************************************************************/
+
+int regval_ctr_delvalue( REGVAL_CTR *ctr, const char *name )
+{
+ int i;
+
+ /* search for the value */
+ if (!(ctr->num_values))
+ return 0;
+
+ for ( i=0; i<ctr->num_values; i++ ) {
+ if ( strcmp( ctr->values[i]->valuename, name ) == 0)
+ break;
+ }
+
+ /* just return if we don't find it */
+
+ if ( i == ctr->num_values )
+ return ctr->num_values;
+
+ /* just shift everything down one */
+
+ for ( /* use previous i */; i<(ctr->num_values-1); i++ )
+ memcpy( ctr->values[i], ctr->values[i+1], sizeof(REGISTRY_VALUE) );
+
+ /* paranoia */
+
+ ZERO_STRUCTP( ctr->values[i] );
+
+ ctr->num_values--;
+
+ return ctr->num_values;
+}
+
+/***********************************************************************
+ Delete a single value from the registry container.
+ No need to free memory since it is talloc'd.
+ **********************************************************************/
+
+REGISTRY_VALUE* regval_ctr_getvalue( REGVAL_CTR *ctr, const char *name )
+{
+ int i;
+
+ /* search for the value */
+
+ for ( i=0; i<ctr->num_values; i++ ) {
+ if ( strequal( ctr->values[i]->valuename, name ) )
+ return ctr->values[i];
+ }
+
+ return NULL;
+}
+
+/***********************************************************************
+ free memory held by a REGVAL_CTR structure
+ **********************************************************************/
+
+void regval_ctr_destroy( REGVAL_CTR *ctr )
+{
+ if ( ctr ) {
+ talloc_destroy( ctr->ctx );
+ ZERO_STRUCTP( ctr );
+ }
+}
+
+
diff --git a/source4/registry/reg_printing.c b/source4/registry/reg_printing.c
new file mode 100644
index 0000000000..619ffc7ee7
--- /dev/null
+++ b/source4/registry/reg_printing.c
@@ -0,0 +1,829 @@
+/*
+ * 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 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 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",
+ 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 = 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 = 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, strlen(filename)+1 );
+ 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, strlen(filename)+1 );
+ 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, strlen(filename)+1 );
+ 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, strlen(filename)+1 );
+ regval_ctr_addvalue( val, "Help File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+
+ init_unistr2( &data, info3->defaultdatatype, strlen(info3->defaultdatatype)+1 );
+ 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 = Realloc( buffer, buffer_size + (length + 1)*sizeof(uint16) );
+ if ( !buffer2 )
+ break;
+ buffer = buffer2;
+
+ init_unistr2( &data, filename, length+1 );
+ 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 = 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 = 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 = 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, strlen(info2->printername)+1 );
+ regval_ctr_addvalue( val, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, info2->location, strlen(info2->location)+1 );
+ regval_ctr_addvalue( val, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, info2->comment, strlen(info2->comment)+1 );
+ regval_ctr_addvalue( val, "Comment", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, info2->parameters, strlen(info2->parameters)+1 );
+ regval_ctr_addvalue( val, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, info2->portname, strlen(info2->portname)+1 );
+ regval_ctr_addvalue( val, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, info2->servername, strlen(info2->servername)+1 );
+ regval_ctr_addvalue( val, "Server", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, info2->sharename, strlen(info2->sharename)+1 );
+ regval_ctr_addvalue( val, "Share", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, info2->drivername, strlen(info2->drivername)+1 );
+ regval_ctr_addvalue( val, "Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, info2->sepfile, strlen(info2->sepfile)+1 );
+ regval_ctr_addvalue( val, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) );
+ init_unistr2( &data, "winprint", strlen("winprint")+1 );
+ 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
+};
+
+