r10656: BIG merge from trunk. Features not copied over
[vlendec/samba-autobuild/.git] / source3 / registry / reg_frontend.c
index 9f8747ef378487913c65add261813c1c10173714..f41c5885bc4d7bdc8710793790ae8ab4e3336c93 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  *  Unix SMB/CIFS implementation.
- *  RPC Pipe client / server routines
- *  Copyright (C) Gerald Carter                     2002.
+ *  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
 
 extern REGISTRY_OPS printing_ops;
 extern REGISTRY_OPS eventlog_ops;
+extern REGISTRY_OPS shares_reg_ops;
 extern REGISTRY_OPS regdb_ops;         /* these are the default */
 
 /* array of REGISTRY_HOOK's which are read into a tree for easy access */
+/* #define REG_TDB_ONLY                1 */
 
 REGISTRY_HOOK reg_hooks[] = {
-  { KEY_PRINTING,   &printing_ops },
-  { KEY_EVENTLOG,   &eventlog_ops }, 
+#ifndef REG_TDB_ONLY 
+  { KEY_PRINTING,              &printing_ops },
+  { KEY_PRINTING_2K,           &printing_ops },
+  { KEY_PRINTING_PORTS,        &printing_ops },
+  { KEY_EVENTLOG,              &eventlog_ops }, 
+  { KEY_SHARES,                &shares_reg_ops },
+#endif
   { NULL, NULL }
 };
 
 
+static struct generic_mapping reg_generic_map = 
+       { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL };
+
+/********************************************************************
+********************************************************************/
+
+static NTSTATUS registry_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token, 
+                                     uint32 access_desired, uint32 *access_granted )
+{
+       NTSTATUS result;
+
+       if ( geteuid() == sec_initial_uid() ) {
+               DEBUG(5,("registry_access_check: using root's token\n"));
+               token = get_root_nt_token();
+       }
+
+       se_map_generic( &access_desired, &reg_generic_map );
+       se_access_check( sec_desc, token, access_desired, access_granted, &result );
+
+       return result;
+}
+
+/********************************************************************
+********************************************************************/
+
+static SEC_DESC* construct_registry_sd( TALLOC_CTX *ctx )
+{
+       SEC_ACE ace[2]; 
+       SEC_ACCESS mask;
+       size_t i = 0;
+       SEC_DESC *sd;
+       SEC_ACL *acl;
+       size_t sd_size;
+
+       /* basic access for Everyone */
+       
+       init_sec_access(&mask, REG_KEY_READ );
+       init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       
+       /* Full Access 'BUILTIN\Administrators' */
+       
+       init_sec_access(&mask, REG_KEY_ALL );
+       init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0);
+       
+       
+       /* create the security descriptor */
+       
+       if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) )
+               return NULL;
+
+       if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) )
+               return NULL;
+
+       return sd;
+}
+
+
 /***********************************************************************
  Open the registry database and initialize the REGISTRY_HOOK cache
  ***********************************************************************/
@@ -46,11 +110,12 @@ 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();
@@ -63,11 +128,16 @@ BOOL init_registry( void )
        if ( DEBUGLEVEL >= 20 )
                reghook_dump_cache(20);
 
-       return True;
-}
+       /* inform the external eventlog machinery of the change */
 
+       eventlog_refresh_external_parameters( get_root_nt_token() );
 
+       /* add any services keys */
 
+       svcctl_init_keys();
+
+       return True;
+}
 
 /***********************************************************************
  High level wrapper function for storing registry subkeys
@@ -75,10 +145,10 @@ BOOL init_registry( void )
  
 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;
+       if ( key->hook && key->hook->ops && key->hook->ops->store_subkeys )
+               return key->hook->ops->store_subkeys( key->name, subkeys );
+               
+       return False;
 
 }
 
@@ -88,10 +158,13 @@ BOOL store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys )
  
 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
+       if ( check_dynamic_reg_values( key ) )
                return False;
+
+       if ( key->hook && key->hook->ops && key->hook->ops->store_values )
+               return key->hook->ops->store_values( key->name, val );
+
+       return False;
 }
 
 
@@ -104,8 +177,8 @@ 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 );
+       if ( key->hook && key->hook->ops && key->hook->ops->fetch_subkeys )
+               result = key->hook->ops->fetch_subkeys( key->name, subkey_ctr );
 
        return result;
 }
@@ -117,9 +190,8 @@ int fetch_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkey_ctr )
 
 BOOL fetch_reg_keys_specific( REGISTRY_KEY *key, char** subkey, uint32 key_index )
 {
-       static REGSUBKEY_CTR ctr;
+       static REGSUBKEY_CTR *ctr = NULL;
        static pstring save_path;
-       static BOOL ctr_init = False;
        char *s;
        
        *subkey = NULL;
@@ -128,33 +200,39 @@ BOOL fetch_reg_keys_specific( REGISTRY_KEY *key, char** subkey, uint32 key_index
 
        DEBUG(8,("fetch_reg_keys_specific: Looking for key [%d] of  [%s]\n", key_index, key->name));
        
-       if ( !ctr_init ) {
+       if ( !ctr ) {
                DEBUG(8,("fetch_reg_keys_specific: Initializing cache of subkeys for [%s]\n", key->name));
-               ZERO_STRUCTP( &ctr );   
-               regsubkey_ctr_init( &ctr );
+
+               if ( !(ctr = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) {
+                       DEBUG(0,("fetch_reg_keys_specific: talloc() failed!\n"));
+                       return False;
+               }
                
                pstrcpy( save_path, key->name );
                
-               if ( fetch_reg_keys( key, &ctr) == -1 )
+               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 );
+               TALLOC_FREE( ctr );
+
+               if ( !(ctr = TALLOC_ZERO_P( NULL, REGSUBKEY_CTR )) ) {
+                       DEBUG(0,("fetch_reg_keys_specific: talloc() failed!\n"));
+                       return False;
+               }
                
                pstrcpy( save_path, key->name );
                
-               if ( fetch_reg_keys( key, &ctr) == -1 )
+               if ( fetch_reg_keys( key, ctr) == -1 )
                        return False;
        }
        
-       if ( !(s = regsubkey_ctr_specific_key( &ctr, key_index )) )
+       if ( !(s = regsubkey_ctr_specific_key( ctr, key_index )) )
                return False;
 
        *subkey = SMB_STRDUP( s );
@@ -162,19 +240,25 @@ BOOL fetch_reg_keys_specific( REGISTRY_KEY *key, char** subkey, uint32 key_index
        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 );
+       if ( key->hook && key->hook->ops && key->hook->ops->fetch_values )
+               result = key->hook->ops->fetch_values( key->name, val );
+       
+       /* if the backend lookup returned no data, try the dynamic overlay */
+       
+       if ( result == 0 ) {
+               result = fetch_dynamic_reg_values( key, val );
 
+               return ( result != -1 ) ? result : 0;
+       }
+       
        return result;
 }
 
@@ -186,43 +270,46 @@ int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
 
 BOOL fetch_reg_values_specific( REGISTRY_KEY *key, REGISTRY_VALUE **val, uint32 val_index )
 {
-       static REGVAL_CTR       ctr;
+       static REGVAL_CTR       *ctr = NULL;
        static pstring          save_path;
-       static BOOL             ctr_init = False;
        REGISTRY_VALUE          *v;
        
        *val = NULL;
        
        /* simple caching for performance; very basic heuristic */
        
-       if ( !ctr_init ) {
+       if ( !ctr ) {
                DEBUG(8,("fetch_reg_values_specific: Initializing cache of values for [%s]\n", key->name));
 
-               ZERO_STRUCTP( &ctr );   
-               regval_ctr_init( &ctr );
-               
+               if ( !(ctr = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
+                       DEBUG(0,("fetch_reg_values_specific: talloc() failed!\n"));
+                       return False;
+               }
+
                pstrcpy( save_path, key->name );
                
-               if ( fetch_reg_values( key, &ctr) == -1 )
+               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) ) {
+       else if ( !val_index || !strequal(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 );
-               
+               TALLOC_FREE( ctr );
+
+               if ( !(ctr = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) {
+                       DEBUG(0,("fetch_reg_values_specific: talloc() failed!\n"));
+                       return False;
+               }
+
                pstrcpy( save_path, key->name );
                
-               if ( fetch_reg_values( key, &ctr) == -1 )
+               if ( fetch_reg_values( key, ctr) == -1 )
                        return False;
        }
        
-       if ( !(v = regval_ctr_specific_value( &ctr, val_index )) )
+       if ( !(v = regval_ctr_specific_value( ctr, val_index )) )
                return False;
 
        *val = dup_registry_value( v );
@@ -231,33 +318,93 @@ BOOL fetch_reg_values_specific( REGISTRY_KEY *key, REGISTRY_VALUE **val, uint32
 }
 
 /***********************************************************************
- 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!
+ High level access check for passing the required access mask to the 
+ underlying registry backend
  ***********************************************************************/
 
-BOOL reg_split_path( char *path, char **base, char **new_path )
+BOOL regkey_access_check( REGISTRY_KEY *key, uint32 requested, uint32 *granted, NT_USER_TOKEN *token )
 {
-       char *p;
+       /* use the default security check if the backend has not defined its own */
        
-       *new_path = *base = NULL;
+       if ( !(key->hook && key->hook->ops && key->hook->ops->reg_access_check) ) {
+               SEC_DESC *sec_desc;
+               NTSTATUS status;
+               
+               if ( !(sec_desc = construct_registry_sd( get_talloc_ctx() )) )
+                       return False;
+               
+               status = registry_access_check( sec_desc, token, requested, granted );          
+               
+               return NT_STATUS_IS_OK(status);
+       }
        
-       if ( !path)
-               return False;
+       return key->hook->ops->reg_access_check( key->name, requested, granted, token );
+}
+
+/***********************************************************************
+***********************************************************************/
+
+WERROR regkey_open_internal( REGISTRY_KEY **regkey, const char *path, 
+                             NT_USER_TOKEN *token, uint32 access_desired )
+{
+       WERROR          result = WERR_OK;
+       REGISTRY_KEY    *keyinfo;
+       REGSUBKEY_CTR   *subkeys = NULL;
+       uint32 access_granted;
+       
+       DEBUG(7,("regkey_open_internal: name = [%s]\n", path));
+
+       if ( !(*regkey = TALLOC_ZERO_P(NULL, REGISTRY_KEY)) )
+               return WERR_NOMEM;
+               
+       keyinfo = *regkey;
+               
+       /* initialization */
        
-       *base = path;
+       keyinfo->type = REG_KEY_GENERIC;
+       keyinfo->name = talloc_strdup( keyinfo, path );
        
-       p = strchr( path, '\\' );
        
-       if ( p ) {
-               *p = '\0';
-               *new_path = p+1;
+       /* Tag this as a Performance Counter Key */
+
+       if( StrnCaseCmp(path, KEY_HKPD, strlen(KEY_HKPD)) == 0 )
+               keyinfo->type = REG_KEY_HKPD;
+       
+       /* Look up the table of registry I/O operations */
+
+       if ( !(keyinfo->hook = reghook_cache_find( keyinfo->name )) ) {
+               DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n",
+                       keyinfo->name ));
+               result = WERR_BADFILE;
+               goto done;
        }
        
-       return True;
-}
+       /* check if the path really exists; failed is indicated by -1 */
+       /* if the subkey count failed, bail out */
 
+       if ( !(subkeys = TALLOC_ZERO_P( keyinfo, REGSUBKEY_CTR )) ) {
+               result = WERR_NOMEM;
+               goto done;
+       }
+
+       if ( fetch_reg_keys( keyinfo, subkeys ) == -1 )  {
+               result = WERR_BADFILE;
+               goto done;
+       }
+       
+       TALLOC_FREE( subkeys );
+
+       if ( !regkey_access_check( keyinfo, access_desired, &access_granted, token ) ) {
+               result = WERR_ACCESS_DENIED;
+               goto done;
+       }
+       
+       keyinfo->access_granted = access_granted;
 
+done:
+       if ( !W_ERROR_IS_OK(result) ) {
+               TALLOC_FREE( *regkey );
+       }
 
+       return result;
+}