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/Makefile.in | 3 +- source3/include/reg_objects.h | 9 +- source3/lib/secdesc.c | 65 +++++++++++- source3/param/loadparm.c | 10 ++ 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 +++++++++++++++ source3/rpc_server/srv_srvsvc_nt.c | 1 + source3/rpc_server/srv_winreg_nt.c | 38 ++++++- source3/smbd/lanman.c | 1 + source3/smbd/msdfs.c | 1 + source3/smbd/service.c | 113 ++++++++++++++++++++ 14 files changed, 566 insertions(+), 67 deletions(-) create mode 100644 source3/registry/reg_smbconf.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 95de6a436a..35355becdf 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -321,7 +321,8 @@ REGOBJS_OBJ = registry/reg_objects.o REGISTRY_OBJ = registry/reg_frontend.o registry/reg_cachehook.o registry/reg_printing.o \ registry/reg_db.o registry/reg_eventlog.o registry/reg_shares.o \ - registry/reg_util.o registry/reg_dynamic.o registry/reg_perfcount.o + registry/reg_util.o registry/reg_dynamic.o registry/reg_perfcount.o \ + registry/reg_smbconf.o RPC_LSA_OBJ = rpc_server/srv_lsa.o rpc_server/srv_lsa_nt.o librpc/gen_ndr/srv_lsa.o diff --git a/source3/include/reg_objects.h b/source3/include/reg_objects.h index 99da22f8cd..e3226b7ae9 100644 --- a/source3/include/reg_objects.h +++ b/source3/include/reg_objects.h @@ -98,6 +98,7 @@ typedef struct { #define KEY_PRINTING_PORTS "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports" #define KEY_EVENTLOG "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Eventlog" #define KEY_SHARES "HKLM\\SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Shares" +#define KEY_SMBCONF "HKLM\\SOFTWARE\\Samba\\smbconf" #define KEY_TREE_ROOT "" /* @@ -121,7 +122,13 @@ typedef struct { int (*fetch_values) ( const char *key, REGVAL_CTR *val ); BOOL (*store_subkeys)( const char *key, REGSUBKEY_CTR *subkeys ); BOOL (*store_values)( const char *key, REGVAL_CTR *val ); - BOOL (*reg_access_check)( const char *keyname, uint32 requested, uint32 *granted, NT_USER_TOKEN *token ); + BOOL (*reg_access_check)( const char *keyname, uint32 requested, + uint32 *granted, + const NT_USER_TOKEN *token ); + WERROR (*get_secdesc)(TALLOC_CTX *mem_ctx, const char *key, + struct security_descriptor **psecdesc); + WERROR (*set_secdesc)(const char *key, + struct security_descriptor *sec_desc); } REGISTRY_OPS; typedef struct { diff --git a/source3/lib/secdesc.c b/source3/lib/secdesc.c index 2f592769b3..762dc2f6d8 100644 --- a/source3/lib/secdesc.c +++ b/source3/lib/secdesc.c @@ -216,16 +216,16 @@ SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision, uint16 type, dst->sacl = NULL; dst->dacl = NULL; - if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL)) + if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL)) goto error_exit; - if(grp_sid && ((dst->group_sid = sid_dup_talloc(ctx,grp_sid)) == NULL)) + if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL)) goto error_exit; - if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL)) + if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL)) goto error_exit; - if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL)) + if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL)) goto error_exit; offset = SEC_DESC_HEADER_SIZE; @@ -274,6 +274,63 @@ SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src) src->dacl, &dummy); } +/******************************************************************* + Convert a secdesc into a byte stream +********************************************************************/ +NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx, + struct security_descriptor *secdesc, + uint8 **data, size_t *len) +{ + prs_struct ps; + + if (!prs_init(&ps, sec_desc_size(secdesc), mem_ctx, MARSHALL)) { + return NT_STATUS_NO_MEMORY; + } + + if (!sec_io_desc("security_descriptor", &secdesc, &ps, 1)) { + prs_mem_free(&ps); + return NT_STATUS_INVALID_PARAMETER; + } + + if (!(*data = (uint8 *)talloc_memdup(mem_ctx, ps.data_p, + prs_offset(&ps)))) { + prs_mem_free(&ps); + return NT_STATUS_NO_MEMORY; + } + + *len = prs_offset(&ps); + prs_mem_free(&ps); + return NT_STATUS_OK; +} + +/******************************************************************* + Parse a byte stream into a secdesc +********************************************************************/ +NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len, + struct security_descriptor **psecdesc) +{ + prs_struct ps; + struct security_descriptor *secdesc = NULL; + + if (!(secdesc = TALLOC_ZERO_P(mem_ctx, struct security_descriptor))) { + return NT_STATUS_NO_MEMORY; + } + + if (!prs_init(&ps, 0, secdesc, UNMARSHALL)) { + return NT_STATUS_NO_MEMORY; + } + + prs_give_memory(&ps, (char *)data, len, False); + + if (!sec_io_desc("security_descriptor", &secdesc, &ps, 1)) { + return NT_STATUS_INVALID_PARAMETER; + } + + prs_mem_free(&ps); + *psecdesc = secdesc; + return NT_STATUS_OK; +} + /******************************************************************* Creates a SEC_DESC structure with typical defaults. ********************************************************************/ diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 81c642daf8..60d686f245 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -304,6 +304,7 @@ typedef struct { BOOL bASUSupport; BOOL bUsershareOwnerOnly; BOOL bUsershareAllowGuests; + BOOL bRegistryShares; int restrict_anonymous; int name_cache_timeout; int client_signing; @@ -1225,6 +1226,7 @@ static struct parm_struct parm_table[] = { {"root preexec close", P_BOOL, P_LOCAL, &sDefault.bRootpreexecClose, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE}, {"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT}, {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT}, + {"registry shares", P_BOOL, P_GLOBAL, &Globals.bRegistryShares, NULL, NULL, FLAG_ADVANCED}, {"usershare allow guests", P_BOOL, P_GLOBAL, &Globals.bUsershareAllowGuests, NULL, NULL, FLAG_ADVANCED}, {"usershare max shares", P_INTEGER, P_GLOBAL, &Globals.iUsershareMaxShares, NULL, NULL, FLAG_ADVANCED}, {"usershare owner only", P_BOOL, P_GLOBAL, &Globals.bUsershareOwnerOnly, NULL, NULL, FLAG_ADVANCED}, @@ -1652,6 +1654,9 @@ static void init_globals(BOOL first_time_only) Globals.bUsershareOwnerOnly = True; /* By default disallow guest access to usershares. */ Globals.bUsershareAllowGuests = False; + + /* By default no shares out of the registry */ + Globals.bRegistryShares = False; } static TALLOC_CTX *lp_talloc; @@ -1860,6 +1865,7 @@ FN_GLOBAL_LIST(lp_usershare_prefix_deny_list, &Globals.szUsersharePrefixDenyList FN_GLOBAL_LIST(lp_eventlog_list, &Globals.szEventLogs) +FN_GLOBAL_BOOL(lp_registry_shares, &Globals.bRegistryShares) FN_GLOBAL_BOOL(lp_usershare_allow_guests, &Globals.bUsershareAllowGuests) FN_GLOBAL_BOOL(lp_usershare_owner_only, &Globals.bUsershareOwnerOnly) FN_GLOBAL_BOOL(lp_disable_netbios, &Globals.bDisableNetbios) @@ -2606,6 +2612,10 @@ BOOL lp_add_home(const char *pszHomename, int iDefaultService, int lp_add_service(const char *pszService, int iDefaultService) { + if (iDefaultService < 0) { + return add_a_service(&sDefault, pszService); + } + return (add_a_service(ServicePtrs[iDefaultService], pszService)); } 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 +}; diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index 35938d087e..ac9a1132e1 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -516,6 +516,7 @@ static WERROR init_srv_share_info_ctr(pipes_struct *p, /* Ensure all the usershares are loaded. */ become_root(); load_usershare_shares(); + load_registry_shares(); unbecome_root(); *total_entries = 0; diff --git a/source3/rpc_server/srv_winreg_nt.c b/source3/rpc_server/srv_winreg_nt.c index 16c271427e..847bc967c5 100644 --- a/source3/rpc_server/srv_winreg_nt.c +++ b/source3/rpc_server/srv_winreg_nt.c @@ -1478,6 +1478,10 @@ WERROR _winreg_DeleteValue(pipes_struct *p, struct policy_handle *handle, struct WERROR _winreg_GetKeySecurity(pipes_struct *p, struct policy_handle *handle, uint32_t sec_info, struct KeySecurityData *sd) { REGISTRY_KEY *key = find_regkey_by_hnd(p, handle); + WERROR err; + struct security_descriptor *secdesc; + uint8 *data; + size_t len; if ( !key ) return WERR_BADFID; @@ -1486,8 +1490,28 @@ WERROR _winreg_GetKeySecurity(pipes_struct *p, struct policy_handle *handle, uin if ( !(key->access_granted & STD_RIGHT_READ_CONTROL_ACCESS) ) return WERR_ACCESS_DENIED; + + err = regkey_get_secdesc(p->mem_ctx, key, &secdesc); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + err = ntstatus_to_werror(marshall_sec_desc(p->mem_ctx, secdesc, + &data, &len)); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + if (len > sd->size) { + sd->size = len; + return WERR_INSUFFICIENT_BUFFER; + } + + sd->size = len; + sd->len = len; + sd->data = data; - return WERR_ACCESS_DENIED; + return WERR_OK; } /******************************************************************* @@ -1496,6 +1520,8 @@ WERROR _winreg_GetKeySecurity(pipes_struct *p, struct policy_handle *handle, uin WERROR _winreg_SetKeySecurity(pipes_struct *p, struct policy_handle *handle, uint32_t access_mask, struct KeySecurityData *sd) { REGISTRY_KEY *key = find_regkey_by_hnd(p, handle); + struct security_descriptor *secdesc; + WERROR err; if ( !key ) return WERR_BADFID; @@ -1504,8 +1530,14 @@ WERROR _winreg_SetKeySecurity(pipes_struct *p, struct policy_handle *handle, uin if ( !(key->access_granted & STD_RIGHT_WRITE_DAC_ACCESS) ) return WERR_ACCESS_DENIED; - - return WERR_ACCESS_DENIED; + + err = ntstatus_to_werror(unmarshall_sec_desc(p->mem_ctx, sd->data, + sd->len, &secdesc)); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + return regkey_set_secdesc(key, secdesc); } /******************************************************************* diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index 8ecc965c0d..e42d96b11e 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -1671,6 +1671,7 @@ static BOOL api_RNetShareEnum( connection_struct *conn, /* Ensure all the usershares are loaded. */ become_root(); + load_registry_shares(); count = load_usershare_shares(); unbecome_root(); diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index 1f04356b4f..12fd333efe 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -1114,6 +1114,7 @@ int enum_msdfs_links(TALLOC_CTX *ctx, struct junction_map *jucn, int jn_max) /* Ensure all the usershares are loaded. */ become_root(); + load_registry_shares(); sharecount = load_usershare_shares(); unbecome_root(); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 60ba85ab65..e63bc01a7d 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -229,6 +229,115 @@ int add_home_service(const char *service, const char *username, const char *home } +static int load_registry_service(const char *servicename) +{ + REGISTRY_KEY *key; + char *path; + WERROR err; + NTSTATUS status; + + uint32 i, num_values; + char **value_names; + struct registry_value **values = NULL; + + int res; + + if (!lp_registry_shares()) { + return -1; + } + + if (asprintf(&path, "%s\\%s", KEY_SMBCONF, servicename) == -1) { + return -1; + } + + err = regkey_open_internal(NULL, NULL, &key, path, get_root_nt_token(), + REG_KEY_READ); + SAFE_FREE(path); + + if (!W_ERROR_IS_OK(err)) { + return -1; + } + + status = registry_fetch_values(NULL, key, &num_values, &value_names, + &values); + + TALLOC_FREE(key); + + if (!NT_STATUS_IS_OK(status)) { + goto error; + } + + res = lp_add_service(servicename, -1); + if (res == -1) { + goto error; + } + + for (i=0; itype) { + case REG_DWORD: { + char *val; + if (asprintf(&val, "%d", values[i]->v.dword) == -1) { + continue; + } + lp_do_parameter(res, value_names[i], val); + SAFE_FREE(val); + break; + } + case REG_SZ: { + lp_do_parameter(res, value_names[i], + values[i]->v.sz.str); + break; + } + default: + /* Ignore all the rest */ + break; + } + } + + TALLOC_FREE(value_names); + TALLOC_FREE(values); + return res; + + error: + + TALLOC_FREE(value_names); + TALLOC_FREE(values); + return -1; +} + +void load_registry_shares(void) +{ + REGISTRY_KEY *key; + REGSUBKEY_CTR *keys; + WERROR err; + int i; + + if (!lp_registry_shares()) { + return; + } + + if (!(keys = TALLOC_ZERO_P(NULL, REGSUBKEY_CTR))) { + goto done; + } + + err = regkey_open_internal(keys, NULL, &key, KEY_SMBCONF, + get_root_nt_token(), REG_KEY_READ); + if (!(W_ERROR_IS_OK(err))) { + goto done; + } + + if (fetch_reg_keys(key, keys) == -1) { + goto done; + } + + for (i=0; inum_subkeys; i++) { + load_registry_service(keys->subkeys[i]); + } + + done: + TALLOC_FREE(keys); + return; +} /** * Find a service entry. @@ -307,6 +416,10 @@ int find_service(fstring service) } } + if (iService < 0) { + iService = load_registry_service(service); + } + /* Is it a usershare service ? */ if (iService < 0 && *lp_usershare_path()) { /* Ensure the name is canonicalized. */ -- cgit