diff options
Diffstat (limited to 'source/registry/reg_frontend.c')
-rw-r--r-- | source/registry/reg_frontend.c | 393 |
1 files changed, 307 insertions, 86 deletions
diff --git a/source/registry/reg_frontend.c b/source/registry/reg_frontend.c index dd904f1863b..ed49cc998c7 100644 --- a/source/registry/reg_frontend.c +++ b/source/registry/reg_frontend.c @@ -28,7 +28,6 @@ extern REGISTRY_OPS printing_ops; extern REGISTRY_OPS eventlog_ops; extern REGISTRY_OPS shares_reg_ops; -extern REGISTRY_OPS smbconf_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 */ @@ -40,11 +39,68 @@ REGISTRY_HOOK reg_hooks[] = { { KEY_PRINTING_2K, &printing_ops }, { KEY_PRINTING_PORTS, &printing_ops }, { KEY_SHARES, &shares_reg_ops }, - { KEY_SMBCONF, &smbconf_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, ®_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 ***********************************************************************/ @@ -84,125 +140,290 @@ BOOL init_registry( void ) return True; } -WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY **regkey, - const char *path, - const struct nt_user_token *token, - uint32 access_desired ) +/*********************************************************************** + High level wrapper function for storing registry subkeys + ***********************************************************************/ + +BOOL store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys ) { - struct registry_key *key; - WERROR err; + if ( key->hook && key->hook->ops && key->hook->ops->store_subkeys ) + return key->hook->ops->store_subkeys( key->name, subkeys ); + + return False; - err = reg_open_path(NULL, path, access_desired, token, &key); - if (!W_ERROR_IS_OK(err)) { - return err; - } +} - *regkey = talloc_move(ctx, &key->key); - TALLOC_FREE(key); - return WERR_OK; +/*********************************************************************** + High level wrapper function for storing registry values + ***********************************************************************/ + +BOOL store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val ) +{ + 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; +} + + +/*********************************************************************** + 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->fetch_subkeys ) + result = key->hook->ops->fetch_subkeys( key->name, subkey_ctr ); + + return result; } -WERROR regkey_set_secdesc(REGISTRY_KEY *key, - struct security_descriptor *psecdesc) +/*********************************************************************** + 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 ) { - if (key->hook && key->hook->ops && key->hook->ops->set_secdesc) { - return key->hook->ops->set_secdesc(key->name, psecdesc); + static REGSUBKEY_CTR *ctr = NULL; + static pstring save_path; + char *s; + + *subkey = NULL; + + /* simple caching for performance; very basic heuristic */ + + DEBUG(8,("fetch_reg_keys_specific: Looking for key [%d] of [%s]\n", key_index, key->name)); + + if ( !ctr ) { + DEBUG(8,("fetch_reg_keys_specific: Initializing cache of subkeys for [%s]\n", key->name)); + + 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 ) + return False; + } + /* 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)); + + 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 ) + return False; + } + + if ( !(s = regsubkey_ctr_specific_key( ctr, key_index )) ) + return False; + + *subkey = SMB_STRDUP( s ); - return WERR_ACCESS_DENIED; + return True; } -/* - * Utility function to create a registry key without opening the hive - * before. Assumes the hive already exists. - */ +/*********************************************************************** + High level wrapper function for enumerating registry values + ***********************************************************************/ -WERROR reg_create_path(TALLOC_CTX *mem_ctx, const char *orig_path, - uint32 desired_access, - const struct nt_user_token *token, - enum winreg_CreateAction *paction, - struct registry_key **pkey) +int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val ) { - struct registry_key *hive; - char *path, *p; - WERROR err; + int result = -1; + + 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 ); - if (!(path = SMB_STRDUP(orig_path))) { - return WERR_NOMEM; + return ( result != -1 ) ? result : 0; } + + return result; +} - p = strchr(path, '\\'); - if ((p == NULL) || (p[1] == '\0')) { - /* - * No key behind the hive, just return the hive - */ +/*********************************************************************** + 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 = NULL; + static pstring save_path; + REGISTRY_VALUE *v; + + *val = NULL; + + /* simple caching for performance; very basic heuristic */ + + if ( !ctr ) { + DEBUG(8,("fetch_reg_values_specific: Initializing cache of values for [%s]\n", key->name)); - err = reg_openhive(mem_ctx, path, desired_access, token, - &hive); - if (!W_ERROR_IS_OK(err)) { - SAFE_FREE(path); - return err; + if ( !(ctr = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) { + DEBUG(0,("fetch_reg_values_specific: talloc() failed!\n")); + return False; } - SAFE_FREE(path); - *pkey = hive; - *paction = REG_OPENED_EXISTING_KEY; - return WERR_OK; + + pstrcpy( save_path, key->name ); + + if ( fetch_reg_values( key, ctr) == -1 ) + return False; } + /* clear the cache when val_index == 0 or the path has changed */ + else if ( !val_index || !strequal(save_path, key->name) ) { - *p = '\0'; + DEBUG(8,("fetch_reg_values_specific: Updating cache of values for [%s]\n", key->name)); + + TALLOC_FREE( ctr ); + + if ( !(ctr = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) { + DEBUG(0,("fetch_reg_values_specific: talloc() failed!\n")); + return False; + } - err = reg_openhive(mem_ctx, path, - (strchr(p+1, '\\') != NULL) ? - SEC_RIGHTS_ENUM_SUBKEYS : SEC_RIGHTS_CREATE_SUBKEY, - token, &hive); - if (!W_ERROR_IS_OK(err)) { - SAFE_FREE(path); - return err; + 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; - err = reg_createkey(mem_ctx, hive, p+1, desired_access, pkey, paction); - SAFE_FREE(path); - TALLOC_FREE(hive); - return err; + *val = dup_registry_value( v ); + + return True; } -/* - * Utility function to create a registry key without opening the hive - * before. Will not delete a hive. - */ +/*********************************************************************** + High level access check for passing the required access mask to the + underlying registry backend + ***********************************************************************/ + +BOOL regkey_access_check( REGISTRY_KEY *key, uint32 requested, uint32 *granted, NT_USER_TOKEN *token ) +{ + /* use the default security check if the backend has not defined its own */ + + 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); + } + + return key->hook->ops->reg_access_check( key->name, requested, granted, token ); +} -WERROR reg_delete_path(const struct nt_user_token *token, - const char *orig_path) +/*********************************************************************** +***********************************************************************/ + +WERROR regkey_open_internal( REGISTRY_KEY **regkey, const char *path, + NT_USER_TOKEN *token, uint32 access_desired ) { - struct registry_key *hive; - char *path, *p; - WERROR err; + WERROR result = WERR_OK; + REGISTRY_KEY *keyinfo; + REGSUBKEY_CTR *subkeys = NULL; + uint32 access_granted; + + if ( !(W_ERROR_IS_OK(result = regdb_open()) ) ) + return result; + + DEBUG(7,("regkey_open_internal: name = [%s]\n", path)); - if (!(path = SMB_STRDUP(orig_path))) { + if ( !(*regkey = TALLOC_ZERO_P(NULL, REGISTRY_KEY)) ) { + regdb_close(); return WERR_NOMEM; } + + keyinfo = *regkey; + + /* initialization */ + + keyinfo->type = REG_KEY_GENERIC; + if (!(keyinfo->name = talloc_strdup(keyinfo, path))) { + result = WERR_NOMEM; + goto done; + } - p = strchr(path, '\\'); + /* 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 ((p == NULL) || (p[1] == '\0')) { - SAFE_FREE(path); - return WERR_INVALID_PARAM; + 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; } + + /* 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 ); - *p = '\0'; + if ( !regkey_access_check( keyinfo, access_desired, &access_granted, token ) ) { + result = WERR_ACCESS_DENIED; + goto done; + } + + keyinfo->access_granted = access_granted; - err = reg_openhive(NULL, path, - (strchr(p+1, '\\') != NULL) ? - SEC_RIGHTS_ENUM_SUBKEYS : SEC_RIGHTS_CREATE_SUBKEY, - token, &hive); - if (!W_ERROR_IS_OK(err)) { - SAFE_FREE(path); - return err; +done: + if ( !W_ERROR_IS_OK(result) ) { + regkey_close_internal( *regkey ); } - err = reg_deletekey(hive, p+1); - SAFE_FREE(path); - TALLOC_FREE(hive); - return err; + return result; +} + +/******************************************************************* +*******************************************************************/ + +WERROR regkey_close_internal( REGISTRY_KEY *key ) +{ + TALLOC_FREE( key ); + regdb_close(); + + return WERR_OK; } |