From 575845ccbeb2acc5dcb5133b80fd19b1d80169f2 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 30 Nov 2006 07:38:40 +0000 Subject: r19963: Add 'registry shares = yes' and registry key security descriptors. (This used to be commit 6cab254c49e07b11c170511ec613f0f33914c3e6) --- source3/registry/reg_db.c | 92 +++++++++++++++++- source3/registry/reg_frontend.c | 211 ++++++++++++++++++++++++++++++---------- source3/registry/reg_printing.c | 2 +- source3/registry/reg_shares.c | 2 +- source3/registry/reg_smbconf.c | 85 ++++++++++++++++ 5 files changed, 334 insertions(+), 58 deletions(-) create mode 100644 source3/registry/reg_smbconf.c (limited to 'source3/registry') diff --git a/source3/registry/reg_db.c b/source3/registry/reg_db.c index 2afecffec7..345193716e 100644 --- a/source3/registry/reg_db.c +++ b/source3/registry/reg_db.c @@ -29,6 +29,7 @@ static TDB_CONTEXT *tdb_reg; static int tdb_refcount; #define VALUE_PREFIX "SAMBA_REGVAL" +#define SECDESC_PREFIX "SAMBA_SECDESC" /* List the deepest path into the registry. All part components will be created.*/ @@ -46,6 +47,7 @@ static const char *builtin_registry_paths[] = { KEY_PRINTING, KEY_SHARES, KEY_EVENTLOG, + KEY_SMBCONF, "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib", "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009", "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors", @@ -661,6 +663,90 @@ BOOL regdb_store_values( const char *key, REGVAL_CTR *values ) return ret != -1 ; } +void normalize_dbkey(char *key) +{ + size_t len = strlen(key); + string_sub(key, "\\", "/", len+1); + strupper_m(key); +} + +static WERROR regdb_get_secdesc(TALLOC_CTX *mem_ctx, const char *key, + struct security_descriptor **psecdesc) +{ + char *tdbkey; + TDB_DATA data; + NTSTATUS status; + + DEBUG(10, ("regdb_get_secdesc: Getting secdesc of key [%s]\n", key)); + + if (asprintf(&tdbkey, "%s/%s", SECDESC_PREFIX, key) == -1) { + return WERR_NOMEM; + } + normalize_dbkey(tdbkey); + + data = tdb_fetch_bystring(tdb_reg, tdbkey); + SAFE_FREE(tdbkey); + + if (data.dptr == NULL) { + return WERR_BADFILE; + } + + status = unmarshall_sec_desc(mem_ctx, (uint8 *)data.dptr, data.dsize, + psecdesc); + + SAFE_FREE(data.dptr); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) { + return WERR_NOMEM; + } + + if (!NT_STATUS_IS_OK(status)) { + return WERR_REG_CORRUPT; + } + + return WERR_OK; +} + +static WERROR regdb_set_secdesc(const char *key, + struct security_descriptor *secdesc) +{ + prs_struct ps; + TALLOC_CTX *mem_ctx; + char *tdbkey; + WERROR err = WERR_NOMEM; + uint8 *data; + TDB_DATA tdbdata; + + if (!(mem_ctx = talloc_init("regdb_set_secdesc"))) { + return WERR_NOMEM; + } + + ZERO_STRUCT(ps); + + if (!(tdbkey = talloc_asprintf(mem_ctx, "%s/%s", SECDESC_PREFIX, + key))) { + goto done; + } + normalize_dbkey(tdbkey); + + err = ntstatus_to_werror(marshall_sec_desc(mem_ctx, secdesc, &data, + &tdbdata.dsize)); + if (!W_ERROR_IS_OK(err)) { + goto done; + } + + tdbdata.dptr = (char *)data; + + if (tdb_trans_store_bystring(tdb_reg, tdbkey, tdbdata, 0) == -1) { + err = ntstatus_to_werror(map_nt_error_from_unix(errno)); + goto done; + } + + done: + prs_mem_free(&ps); + TALLOC_FREE(mem_ctx); + return err; +} /* * Table of function pointers for default access @@ -671,7 +757,7 @@ REGISTRY_OPS regdb_ops = { regdb_fetch_values, regdb_store_keys, regdb_store_values, - NULL + NULL, + regdb_get_secdesc, + regdb_set_secdesc }; - - diff --git a/source3/registry/reg_frontend.c b/source3/registry/reg_frontend.c index 90b068dcb9..79fbc8ef52 100644 --- a/source3/registry/reg_frontend.c +++ b/source3/registry/reg_frontend.c @@ -28,6 +28,7 @@ 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 */ @@ -39,6 +40,7 @@ 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 } }; @@ -50,25 +52,6 @@ static struct generic_mapping reg_generic_map = /******************************************************************** ********************************************************************/ -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]; @@ -268,23 +251,46 @@ NTSTATUS registry_fetch_values(TALLOC_CTX *mem_ctx, REGISTRY_KEY *key, underlying registry backend ***********************************************************************/ -BOOL regkey_access_check( REGISTRY_KEY *key, uint32 requested, uint32 *granted, NT_USER_TOKEN *token ) +BOOL regkey_access_check( REGISTRY_KEY *key, uint32 requested, uint32 *granted, + const struct 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); + SEC_DESC *sec_desc; + NTSTATUS status; + WERROR err; + TALLOC_CTX *mem_ctx; + + /* 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) { + return key->hook->ops->reg_access_check( key->name, requested, + granted, token ); } - - return key->hook->ops->reg_access_check( key->name, requested, granted, token ); + + /* + * The secdesc routines can't yet cope with a NULL talloc ctx sanely. + */ + + if (!(mem_ctx = talloc_init("regkey_access_check"))) { + return False; + } + + err = regkey_get_secdesc(mem_ctx, key, &sec_desc); + + if (!W_ERROR_IS_OK(err)) { + TALLOC_FREE(mem_ctx); + return False; + } + + se_map_generic( &requested, ®_generic_map ); + + if (!se_access_check(sec_desc, token, requested, granted, &status)) { + TALLOC_FREE(mem_ctx); + return False; + } + + TALLOC_FREE(mem_ctx); + return NT_STATUS_IS_OK(status); } /*********************************************************************** @@ -295,17 +301,22 @@ static int regkey_destructor(REGISTRY_KEY *key) return regdb_close(); } -WERROR regkey_open_internal( TALLOC_CTX *mem_ctx, REGISTRY_KEY *parent, +WERROR regkey_open_onelevel( TALLOC_CTX *mem_ctx, REGISTRY_KEY *parent, REGISTRY_KEY **regkey, const char *name, - NT_USER_TOKEN *token, uint32 access_desired ) + const struct nt_user_token *token, + uint32 access_desired ) { WERROR result = WERR_OK; REGISTRY_KEY *key; REGSUBKEY_CTR *subkeys = NULL; - size_t path_len; DEBUG(7,("regkey_open_internal: name = [%s]\n", name)); + if ((parent != NULL) && + ((parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) == 0)) { + return WERR_ACCESS_DENIED; + } + if ( !(key = TALLOC_ZERO_P(mem_ctx, REGISTRY_KEY)) ) { return WERR_NOMEM; } @@ -320,27 +331,30 @@ WERROR regkey_open_internal( TALLOC_CTX *mem_ctx, REGISTRY_KEY *parent, /* initialization */ key->type = REG_KEY_GENERIC; - if (!(key->name = talloc_strdup(key, name))) { - result = WERR_NOMEM; - goto done; - } - if (parent != NULL) { - char *tmp; - if (!(tmp = talloc_asprintf(key, "%s%s%s", - parent ? parent->name : "", - parent ? "\\" : "", - key->name))) { - result = WERR_NOMEM; + if (name[0] == '\0') { + /* + * Open a copy of the parent key + */ + if (!parent) { + result = WERR_BADFILE; goto done; } - TALLOC_FREE(key->name); - key->name = tmp; + key->name = talloc_strdup(key, parent->name); + } + else { + /* + * Normal open, concat parent and new keynames + */ + key->name = talloc_asprintf(key, "%s%s%s", + parent ? parent->name : "", + parent ? "\\": "", + name); } - path_len = strlen( key->name ); - if ( (path_len != 0) && (key->name[path_len-1] == '\\') ) { - key->name[path_len-1] = '\0'; + if (key->name == NULL) { + result = WERR_NOMEM; + goto done; } /* Tag this as a Performance Counter Key */ @@ -388,3 +402,94 @@ done: return result; } + +WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY *parent, + REGISTRY_KEY **regkey, const char *name, + NT_USER_TOKEN *token, uint32 access_desired ) +{ + TALLOC_CTX *mem_ctx; + const char *p; + BOOL free_parent = False; + WERROR err; + size_t len; + + if (!(mem_ctx = talloc_new(ctx))) { + return WERR_NOMEM; + } + + len = strlen(name); + if ((len > 0) && (name[len-1] == '\\')) { + if (!(name = talloc_strndup(mem_ctx, name, len-1))) { + TALLOC_FREE(mem_ctx); + return WERR_NOMEM; + } + } + + while ((p = strchr(name, '\\')) != NULL) { + char *name_component; + REGISTRY_KEY *intermediate; + + + if (!(name_component = talloc_strndup( + mem_ctx, name, (p - name)))) { + TALLOC_FREE(mem_ctx); + return WERR_NOMEM; + } + + err = regkey_open_onelevel(mem_ctx, parent, &intermediate, + name_component, token, + SEC_RIGHTS_ENUM_SUBKEYS); + TALLOC_FREE(name_component); + + if (!W_ERROR_IS_OK(err)) { + TALLOC_FREE(mem_ctx); + return WERR_NOMEM; + } + + if (free_parent) { + TALLOC_FREE(parent); + } + parent = intermediate; + free_parent = True; + name = p+1; + } + + err = regkey_open_onelevel(ctx, parent, regkey, name, token, + access_desired); + TALLOC_FREE(mem_ctx); + return err; +} + +WERROR regkey_get_secdesc(TALLOC_CTX *mem_ctx, REGISTRY_KEY *key, + struct security_descriptor **psecdesc) +{ + struct security_descriptor *secdesc; + + if (key->hook && key->hook->ops && key->hook->ops->get_secdesc) { + WERROR err; + + err = key->hook->ops->get_secdesc(mem_ctx, key->name, + psecdesc); + if (W_ERROR_IS_OK(err)) { + return WERR_OK; + } + } + + if (!(secdesc = construct_registry_sd(mem_ctx))) { + return WERR_NOMEM; + } + + *psecdesc = secdesc; + return WERR_OK; +} + +WERROR regkey_set_secdesc(REGISTRY_KEY *key, + struct security_descriptor *psecdesc) +{ + if (key->hook && key->hook->ops && key->hook->ops->set_secdesc) { + return key->hook->ops->set_secdesc(key->name, psecdesc); + } + + return WERR_ACCESS_DENIED; +} + diff --git a/source3/registry/reg_printing.c b/source3/registry/reg_printing.c index ba79092ea5..c20d5ab96f 100644 --- a/source3/registry/reg_printing.c +++ b/source3/registry/reg_printing.c @@ -1239,7 +1239,7 @@ REGISTRY_OPS printing_ops = { regprint_fetch_reg_values, regprint_store_reg_keys, regprint_store_reg_values, - NULL + NULL, NULL, NULL }; diff --git a/source3/registry/reg_shares.c b/source3/registry/reg_shares.c index 5a3e9a131b..d2113a647d 100644 --- a/source3/registry/reg_shares.c +++ b/source3/registry/reg_shares.c @@ -160,7 +160,7 @@ REGISTRY_OPS shares_reg_ops = { shares_value_info, shares_store_subkey, shares_store_value, - NULL + NULL, NULL, NULL }; diff --git a/source3/registry/reg_smbconf.c b/source3/registry/reg_smbconf.c new file mode 100644 index 0000000000..b17422fdcb --- /dev/null +++ b/source3/registry/reg_smbconf.c @@ -0,0 +1,85 @@ +/* + * Unix SMB/CIFS implementation. + * Virtual Windows Registry Layer + * Copyright (C) Volker Lendecke 2006 + * + * 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. + */ + +#include "includes.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +extern REGISTRY_OPS regdb_ops; /* these are the default */ + +static int smbconf_fetch_keys( const char *key, REGSUBKEY_CTR *subkey_ctr ) +{ + return regdb_ops.fetch_subkeys(key, subkey_ctr); +} + +static BOOL smbconf_store_keys( const char *key, REGSUBKEY_CTR *subkeys ) +{ + return regdb_ops.store_subkeys(key, subkeys); +} + +static int smbconf_fetch_values( const char *key, REGVAL_CTR *val ) +{ + return regdb_ops.fetch_values(key, val); +} + +static BOOL smbconf_store_values( const char *key, REGVAL_CTR *val ) +{ + return regdb_ops.store_values(key, val); +} + +static BOOL smbconf_reg_access_check(const char *keyname, uint32 requested, + uint32 *granted, + const struct nt_user_token *token) +{ + if (!(user_has_privileges(token, &se_disk_operators))) { + return False; + } + + *granted = REG_KEY_ALL; + return True; +} + +static WERROR smbconf_get_secdesc(TALLOC_CTX *mem_ctx, const char *key, + struct security_descriptor **psecdesc) +{ + return regdb_ops.get_secdesc(mem_ctx, key, psecdesc); +} + +static WERROR smbconf_set_secdesc(const char *key, + struct security_descriptor *secdesc) +{ + return regdb_ops.set_secdesc(key, secdesc); +} + + +/* + * Table of function pointers for accessing smb.conf data + */ + +REGISTRY_OPS smbconf_reg_ops = { + smbconf_fetch_keys, + smbconf_fetch_values, + smbconf_store_keys, + smbconf_store_values, + smbconf_reg_access_check, + smbconf_get_secdesc, + smbconf_set_secdesc +}; -- cgit