From a40df6f92d42676a9184fb2c20a11d5662ca5b3a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 9 Apr 2007 10:38:55 +0000 Subject: r22135: Check in most of Michael Adam's net conf utility. A good share of this patch is moving functions around to fix some linker dependencies for the registry. Michael, I've renamed your auth_utils2.c to token_utils.c. Thanks! Volker (This used to be commit 9de16f25c1c3e0b203da47391772ef2e2fe291ac) --- source3/Makefile.in | 28 +- source3/auth/auth_util.c | 432 ------------- source3/auth/token_util.c | 458 ++++++++++++++ source3/registry/reg_api.c | 60 ++ source3/registry/reg_frontend.c | 346 ---------- source3/registry/reg_frontend_hilvl.c | 315 ++++++++++ source3/utils/net.c | 3 + source3/utils/net.h | 1 + source3/utils/net_conf.c | 1118 +++++++++++++++++++++++++++++++++ 9 files changed, 1977 insertions(+), 784 deletions(-) create mode 100644 source3/auth/token_util.c create mode 100644 source3/registry/reg_frontend_hilvl.c create mode 100644 source3/utils/net_conf.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 2e148a010c..e190c70e24 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -341,7 +341,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_smbconf.o registry/reg_api.o + registry/reg_smbconf.o registry/reg_api.o \ + registry/reg_frontend_hilvl.o RPC_LSA_OBJ = rpc_server/srv_lsa.o rpc_server/srv_lsa_nt.o librpc/gen_ndr/srv_lsa.o @@ -462,8 +463,8 @@ AUTH_UNIX_OBJ = auth/auth_unix.o AUTH_WINBIND_OBJ = auth/auth_winbind.o AUTH_SCRIPT_OBJ = auth/auth_script.o -AUTH_OBJ = auth/auth.o @AUTH_STATIC@ auth/auth_util.o auth/auth_compat.o \ - auth/auth_ntlmssp.o \ +AUTH_OBJ = auth/auth.o @AUTH_STATIC@ auth/auth_util.o auth/token_util.o \ + auth/auth_compat.o auth/auth_ntlmssp.o \ $(PLAINTEXT_AUTH_OBJ) $(SLCACHE_OBJ) $(DCUTIL_OBJ) MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o @@ -639,8 +640,22 @@ NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_domain.o utils/net_help.o \ utils/net_rpc_service.o utils/net_rpc_registry.o utils/net_usershare.o \ utils/netlookup.o utils/net_sam.o utils/net_rpc_shell.o \ utils/net_util.o utils/net_rpc_sh_acct.o utils/net_rpc_audit.o \ - $(PASSWD_UTIL_OBJ) utils/net_dns.o utils/net_ads_gpo.o - + $(PASSWD_UTIL_OBJ) utils/net_dns.o utils/net_ads_gpo.o \ + utils/net_conf.o + +NET_REG_OBJ = registry/reg_api.o \ + registry/reg_frontend_hilvl.o \ + registry/reg_smbconf.o \ + registry/reg_db.o \ + registry/reg_util.o \ + \ + registry/reg_cachehook.o \ + registry/reg_eventlog.o \ + registry/reg_perfcount.o \ + registry/reg_dynamic.o \ + \ + auth/token_util.o + NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \ $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ $(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) $(LIBADDNS_OBJ0) \ @@ -648,7 +663,8 @@ NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \ $(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ) \ $(SMBLDAP_OBJ) $(DCUTIL_OBJ) $(SERVER_MUTEX_OBJ) \ $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(REGFIO_OBJ) $(READLINE_OBJ) \ - $(LDB_OBJ) $(LIBGPO_OBJ) $(INIPARSER_OBJ) $(DISPLAY_SEC_OBJ) + $(LDB_OBJ) $(LIBGPO_OBJ) $(INIPARSER_OBJ) $(DISPLAY_SEC_OBJ) \ + $(NET_REG_OBJ) CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) \ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(SECRETS_OBJ) diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 7891ce1599..0de3bf2325 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -27,12 +27,6 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_AUTH -static struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx, - const DOM_SID *user_sid, - BOOL is_guest, - int num_groupsids, - const DOM_SID *groupsids); - /**************************************************************************** Create a UNIX user on demand. ****************************************************************************/ @@ -481,38 +475,6 @@ void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid, (long int)groups[i])); } -/****************************************************************************** - Create a token for the root user to be used internally by smbd. - This is similar to running under the context of the LOCAL_SYSTEM account - in Windows. This is a read-only token. Do not modify it or free() it. - Create a copy if your need to change it. -******************************************************************************/ - -NT_USER_TOKEN *get_root_nt_token( void ) -{ - static NT_USER_TOKEN *token = NULL; - DOM_SID u_sid, g_sid; - struct passwd *pw; - - if ( token ) - return token; - - if ( !(pw = sys_getpwnam( "root" )) ) { - DEBUG(0,("get_root_nt_token: getpwnam\"root\") failed!\n")); - return NULL; - } - - /* get the user and primary group SIDs; although the - BUILTIN\Administrators SId is really the one that matters here */ - - uid_to_sid(&u_sid, pw->pw_uid); - gid_to_sid(&g_sid, pw->pw_gid); - - token = create_local_nt_token(NULL, &u_sid, False, - 1, &global_sid_Builtin_Administrators); - return token; -} - static int server_info_dtor(auth_serversupplied_info *server_info) { TALLOC_FREE(server_info->sam_account); @@ -631,53 +593,6 @@ NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info, return NT_STATUS_OK; } -/* - * Add alias SIDs from memberships within the partially created token SID list - */ - -static NTSTATUS add_aliases(const DOM_SID *domain_sid, - struct nt_user_token *token) -{ - uint32 *aliases; - size_t i, num_aliases; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; - - if (!(tmp_ctx = talloc_init("add_aliases"))) { - return NT_STATUS_NO_MEMORY; - } - - aliases = NULL; - num_aliases = 0; - - status = pdb_enum_alias_memberships(tmp_ctx, domain_sid, - token->user_sids, - token->num_sids, - &aliases, &num_aliases); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("pdb_enum_alias_memberships failed: %s\n", - nt_errstr(status))); - TALLOC_FREE(tmp_ctx); - return status; - } - - for (i=0; iuser_sids, - &token->num_sids)) { - DEBUG(0, ("add_sid_to_array failed\n")); - TALLOC_FREE(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - } - - TALLOC_FREE(tmp_ctx); - return NT_STATUS_OK; -} - static NTSTATUS log_nt_token(TALLOC_CTX *tmp_ctx, NT_USER_TOKEN *token) { char *command; @@ -714,270 +629,6 @@ static NTSTATUS log_nt_token(TALLOC_CTX *tmp_ctx, NT_USER_TOKEN *token) return NT_STATUS_OK; } -/******************************************************************* -*******************************************************************/ - -static NTSTATUS add_builtin_administrators( struct nt_user_token *token ) -{ - DOM_SID domadm; - - /* nothing to do if we aren't in a domain */ - - if ( !(IS_DC || lp_server_role()==ROLE_DOMAIN_MEMBER) ) { - return NT_STATUS_OK; - } - - /* Find the Domain Admins SID */ - - if ( IS_DC ) { - sid_copy( &domadm, get_global_sam_sid() ); - } else { - if ( !secrets_fetch_domain_sid( lp_workgroup(), &domadm ) ) - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } - sid_append_rid( &domadm, DOMAIN_GROUP_RID_ADMINS ); - - /* Add Administrators if the user beloongs to Domain Admins */ - - if ( nt_token_check_sid( &domadm, token ) ) { - if (!add_sid_to_array(token, &global_sid_Builtin_Administrators, - &token->user_sids, &token->num_sids)) { - return NT_STATUS_NO_MEMORY; - } - } - - return NT_STATUS_OK; -} - -/******************************************************************* -*******************************************************************/ - -static NTSTATUS create_builtin_users( void ) -{ - NTSTATUS status; - DOM_SID dom_users; - - status = pdb_create_builtin_alias( BUILTIN_ALIAS_RID_USERS ); - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(0,("create_builtin_users: Failed to create Users\n")); - return status; - } - - /* add domain users */ - if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER)) - && secrets_fetch_domain_sid(lp_workgroup(), &dom_users)) - { - sid_append_rid(&dom_users, DOMAIN_GROUP_RID_USERS ); - status = pdb_add_aliasmem( &global_sid_Builtin_Users, &dom_users); - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(0,("create_builtin_users: Failed to add Domain Users to" - " Users\n")); - return status; - } - } - - return NT_STATUS_OK; -} - -/******************************************************************* -*******************************************************************/ - -static NTSTATUS create_builtin_administrators( void ) -{ - NTSTATUS status; - DOM_SID dom_admins, root_sid; - fstring root_name; - enum lsa_SidType type; - TALLOC_CTX *ctx; - BOOL ret; - - status = pdb_create_builtin_alias( BUILTIN_ALIAS_RID_ADMINS ); - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(0,("create_builtin_administrators: Failed to create Administrators\n")); - return status; - } - - /* add domain admins */ - if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER)) - && secrets_fetch_domain_sid(lp_workgroup(), &dom_admins)) - { - sid_append_rid(&dom_admins, DOMAIN_GROUP_RID_ADMINS); - status = pdb_add_aliasmem( &global_sid_Builtin_Administrators, &dom_admins ); - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(0,("create_builtin_administrators: Failed to add Domain Admins" - " Administrators\n")); - return status; - } - } - - /* add root */ - if ( (ctx = talloc_init("create_builtin_administrators")) == NULL ) { - return NT_STATUS_NO_MEMORY; - } - fstr_sprintf( root_name, "%s\\root", get_global_sam_name() ); - ret = lookup_name( ctx, root_name, 0, NULL, NULL, &root_sid, &type ); - TALLOC_FREE( ctx ); - - if ( ret ) { - status = pdb_add_aliasmem( &global_sid_Builtin_Administrators, &root_sid ); - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(0,("create_builtin_administrators: Failed to add root" - " Administrators\n")); - return status; - } - } - - return NT_STATUS_OK; -} - -/******************************************************************* - Create a NT token for the user, expanding local aliases -*******************************************************************/ - -static struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx, - const DOM_SID *user_sid, - BOOL is_guest, - int num_groupsids, - const DOM_SID *groupsids) -{ - struct nt_user_token *result = NULL; - int i; - NTSTATUS status; - gid_t gid; - - DEBUG(10, ("Create local NT token for %s\n", sid_string_static(user_sid))); - - if (!(result = TALLOC_ZERO_P(mem_ctx, NT_USER_TOKEN))) { - DEBUG(0, ("talloc failed\n")); - return NULL; - } - - /* Add the user and primary group sid */ - - if (!add_sid_to_array(result, user_sid, - &result->user_sids, &result->num_sids)) { - return NULL; - } - - /* For guest, num_groupsids may be zero. */ - if (num_groupsids) { - if (!add_sid_to_array(result, &groupsids[0], - &result->user_sids, &result->num_sids)) { - return NULL; - } - } - - /* Add in BUILTIN sids */ - - if (!add_sid_to_array(result, &global_sid_World, - &result->user_sids, &result->num_sids)) { - return NULL; - } - if (!add_sid_to_array(result, &global_sid_Network, - &result->user_sids, &result->num_sids)) { - return NULL; - } - - if (is_guest) { - if (!add_sid_to_array(result, &global_sid_Builtin_Guests, - &result->user_sids, &result->num_sids)) { - return NULL; - } - } else { - if (!add_sid_to_array(result, &global_sid_Authenticated_Users, - &result->user_sids, &result->num_sids)) { - return NULL; - } - } - - /* Now the SIDs we got from authentication. These are the ones from - * the info3 struct or from the pdb_enum_group_memberships, depending - * on who authenticated the user. - * Note that we start the for loop at "1" here, we already added the - * first group sid as primary above. */ - - for (i=1; iuser_sids, &result->num_sids)) { - return NULL; - } - } - - /* Deal with the BUILTIN\Administrators group. If the SID can - be resolved then assume that the add_aliasmem( S-1-5-32 ) - handled it. */ - - if ( !sid_to_gid( &global_sid_Builtin_Administrators, &gid ) ) { - /* We can only create a mapping if winbind is running - and the nested group functionality has been enabled */ - - if ( lp_winbind_nested_groups() && winbind_ping() ) { - become_root(); - status = create_builtin_administrators( ); - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(2,("create_local_nt_token: Failed to create BUILTIN\\Administrators group!\n")); - /* don't fail, just log the message */ - } - unbecome_root(); - } - else { - status = add_builtin_administrators( result ); - if ( !NT_STATUS_IS_OK(status) ) { - /* just log a complaint but do not fail */ - DEBUG(3,("create_local_nt_token: failed to check for local Administrators" - " membership (%s)\n", nt_errstr(status))); - } - } - } - - /* Deal with the BUILTIN\Users group. If the SID can - be resolved then assume that the add_aliasmem( S-1-5-32 ) - handled it. */ - - if ( !sid_to_gid( &global_sid_Builtin_Users, &gid ) ) { - /* We can only create a mapping if winbind is running - and the nested group functionality has been enabled */ - - if ( lp_winbind_nested_groups() && winbind_ping() ) { - become_root(); - status = create_builtin_users( ); - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(2,("create_local_nt_token: Failed to create BUILTIN\\Users group!\n")); - /* don't fail, just log the message */ - } - unbecome_root(); - } - } - - /* Deal with local groups */ - - if (lp_winbind_nested_groups()) { - - /* Now add the aliases. First the one from our local SAM */ - - status = add_aliases(get_global_sam_sid(), result); - - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(result); - return NULL; - } - - /* Finally the builtin ones */ - - status = add_aliases(&global_sid_Builtin, result); - - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(result); - return NULL; - } - } - - - get_privileges_for_sids(&result->privileges, result->user_sids, - result->num_sids); - return result; -} - /* * Create the token to use from server_info->sam_account and * server_info->sids (the info3/sam groups). Find the unix gids. @@ -2039,89 +1690,6 @@ BOOL make_auth_methods(struct auth_context *auth_context, auth_methods **auth_me return True; } -/**************************************************************************** - Duplicate a SID token. -****************************************************************************/ - -NT_USER_TOKEN *dup_nt_token(TALLOC_CTX *mem_ctx, const NT_USER_TOKEN *ptoken) -{ - NT_USER_TOKEN *token; - - if (!ptoken) - return NULL; - - token = TALLOC_P(mem_ctx, NT_USER_TOKEN); - if (token == NULL) { - DEBUG(0, ("talloc failed\n")); - return NULL; - } - - ZERO_STRUCTP(token); - - if (ptoken->user_sids && ptoken->num_sids) { - token->user_sids = (DOM_SID *)talloc_memdup( - token, ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids ); - - if (token->user_sids == NULL) { - DEBUG(0, ("talloc_memdup failed\n")); - TALLOC_FREE(token); - return NULL; - } - token->num_sids = ptoken->num_sids; - } - - /* copy the privileges; don't consider failure to be critical here */ - - if ( !se_priv_copy( &token->privileges, &ptoken->privileges ) ) { - DEBUG(0,("dup_nt_token: Failure to copy SE_PRIV!. " - "Continuing with 0 privileges assigned.\n")); - } - - return token; -} - -/**************************************************************************** - Check for a SID in an NT_USER_TOKEN -****************************************************************************/ - -BOOL nt_token_check_sid ( const DOM_SID *sid, const NT_USER_TOKEN *token ) -{ - int i; - - if ( !sid || !token ) - return False; - - for ( i=0; inum_sids; i++ ) { - if ( sid_equal( sid, &token->user_sids[i] ) ) - return True; - } - - return False; -} - -BOOL nt_token_check_domain_rid( NT_USER_TOKEN *token, uint32 rid ) -{ - DOM_SID domain_sid; - - /* if we are a domain member, the get the domain SID, else for - a DC or standalone server, use our own SID */ - - if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) { - if ( !secrets_fetch_domain_sid( lp_workgroup(), - &domain_sid ) ) { - DEBUG(1,("nt_token_check_domain_rid: Cannot lookup " - "SID for domain [%s]\n", lp_workgroup())); - return False; - } - } - else - sid_copy( &domain_sid, get_global_sam_sid() ); - - sid_append_rid( &domain_sid, rid ); - - return nt_token_check_sid( &domain_sid, token );\ -} - /** * Verify whether or not given domain is trusted. * diff --git a/source3/auth/token_util.c b/source3/auth/token_util.c new file mode 100644 index 0000000000..1eb9d12ab5 --- /dev/null +++ b/source3/auth/token_util.c @@ -0,0 +1,458 @@ +/* + * Unix SMB/CIFS implementation. + * Authentication utility functions + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Andrew Bartlett 2001 + * Copyright (C) Jeremy Allison 2000-2001 + * Copyright (C) Rafal Szczesniak 2002 + * Copyright (C) Volker Lendecke 2006 + * Copyright (C) Michael Adam 2007 + * + * 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. + */ + +/* functions moved from auth/auth_util.c to minimize linker deps */ + +#include "includes.h" + +/**************************************************************************** + Duplicate a SID token. +****************************************************************************/ + +NT_USER_TOKEN *dup_nt_token(TALLOC_CTX *mem_ctx, const NT_USER_TOKEN *ptoken) +{ + NT_USER_TOKEN *token; + + if (!ptoken) + return NULL; + + token = TALLOC_P(mem_ctx, NT_USER_TOKEN); + if (token == NULL) { + DEBUG(0, ("talloc failed\n")); + return NULL; + } + + ZERO_STRUCTP(token); + + if (ptoken->user_sids && ptoken->num_sids) { + token->user_sids = (DOM_SID *)talloc_memdup( + token, ptoken->user_sids, sizeof(DOM_SID) * ptoken->num_sids ); + + if (token->user_sids == NULL) { + DEBUG(0, ("talloc_memdup failed\n")); + TALLOC_FREE(token); + return NULL; + } + token->num_sids = ptoken->num_sids; + } + + /* copy the privileges; don't consider failure to be critical here */ + + if ( !se_priv_copy( &token->privileges, &ptoken->privileges ) ) { + DEBUG(0,("dup_nt_token: Failure to copy SE_PRIV!. " + "Continuing with 0 privileges assigned.\n")); + } + + return token; +} + +/**************************************************************************** + Check for a SID in an NT_USER_TOKEN +****************************************************************************/ + +BOOL nt_token_check_sid ( const DOM_SID *sid, const NT_USER_TOKEN *token ) +{ + int i; + + if ( !sid || !token ) + return False; + + for ( i=0; inum_sids; i++ ) { + if ( sid_equal( sid, &token->user_sids[i] ) ) + return True; + } + + return False; +} + +BOOL nt_token_check_domain_rid( NT_USER_TOKEN *token, uint32 rid ) +{ + DOM_SID domain_sid; + + /* if we are a domain member, the get the domain SID, else for + a DC or standalone server, use our own SID */ + + if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) { + if ( !secrets_fetch_domain_sid( lp_workgroup(), + &domain_sid ) ) { + DEBUG(1,("nt_token_check_domain_rid: Cannot lookup " + "SID for domain [%s]\n", lp_workgroup())); + return False; + } + } + else + sid_copy( &domain_sid, get_global_sam_sid() ); + + sid_append_rid( &domain_sid, rid ); + + return nt_token_check_sid( &domain_sid, token );\ +} + +/****************************************************************************** + Create a token for the root user to be used internally by smbd. + This is similar to running under the context of the LOCAL_SYSTEM account + in Windows. This is a read-only token. Do not modify it or free() it. + Create a copy if your need to change it. +******************************************************************************/ + +NT_USER_TOKEN *get_root_nt_token( void ) +{ + static NT_USER_TOKEN *token = NULL; + DOM_SID u_sid, g_sid; + struct passwd *pw; + + if ( token ) + return token; + + if ( !(pw = sys_getpwnam( "root" )) ) { + DEBUG(0,("get_root_nt_token: getpwnam\"root\") failed!\n")); + return NULL; + } + + /* get the user and primary group SIDs; although the + BUILTIN\Administrators SId is really the one that matters here */ + + uid_to_sid(&u_sid, pw->pw_uid); + gid_to_sid(&g_sid, pw->pw_gid); + + token = create_local_nt_token(NULL, &u_sid, False, + 1, &global_sid_Builtin_Administrators); + return token; +} + + +/* + * Add alias SIDs from memberships within the partially created token SID list + */ + +static NTSTATUS add_aliases(const DOM_SID *domain_sid, + struct nt_user_token *token) +{ + uint32 *aliases; + size_t i, num_aliases; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + if (!(tmp_ctx = talloc_init("add_aliases"))) { + return NT_STATUS_NO_MEMORY; + } + + aliases = NULL; + num_aliases = 0; + + status = pdb_enum_alias_memberships(tmp_ctx, domain_sid, + token->user_sids, + token->num_sids, + &aliases, &num_aliases); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("pdb_enum_alias_memberships failed: %s\n", + nt_errstr(status))); + TALLOC_FREE(tmp_ctx); + return status; + } + + for (i=0; iuser_sids, + &token->num_sids)) { + DEBUG(0, ("add_sid_to_array failed\n")); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + } + + TALLOC_FREE(tmp_ctx); + return NT_STATUS_OK; +} + +/******************************************************************* +*******************************************************************/ + +static NTSTATUS add_builtin_administrators( struct nt_user_token *token ) +{ + DOM_SID domadm; + + /* nothing to do if we aren't in a domain */ + + if ( !(IS_DC || lp_server_role()==ROLE_DOMAIN_MEMBER) ) { + return NT_STATUS_OK; + } + + /* Find the Domain Admins SID */ + + if ( IS_DC ) { + sid_copy( &domadm, get_global_sam_sid() ); + } else { + if ( !secrets_fetch_domain_sid( lp_workgroup(), &domadm ) ) + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + sid_append_rid( &domadm, DOMAIN_GROUP_RID_ADMINS ); + + /* Add Administrators if the user beloongs to Domain Admins */ + + if ( nt_token_check_sid( &domadm, token ) ) { + if (!add_sid_to_array(token, &global_sid_Builtin_Administrators, + &token->user_sids, &token->num_sids)) { + return NT_STATUS_NO_MEMORY; + } + } + + return NT_STATUS_OK; +} + +/******************************************************************* +*******************************************************************/ + +static NTSTATUS create_builtin_users( void ) +{ + NTSTATUS status; + DOM_SID dom_users; + + status = pdb_create_builtin_alias( BUILTIN_ALIAS_RID_USERS ); + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(0,("create_builtin_users: Failed to create Users\n")); + return status; + } + + /* add domain users */ + if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER)) + && secrets_fetch_domain_sid(lp_workgroup(), &dom_users)) + { + sid_append_rid(&dom_users, DOMAIN_GROUP_RID_USERS ); + status = pdb_add_aliasmem( &global_sid_Builtin_Users, &dom_users); + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(0,("create_builtin_administrators: Failed to add Domain Users to" + " Users\n")); + return status; + } + } + + return NT_STATUS_OK; +} + +/******************************************************************* +*******************************************************************/ + +static NTSTATUS create_builtin_administrators( void ) +{ + NTSTATUS status; + DOM_SID dom_admins, root_sid; + fstring root_name; + enum lsa_SidType type; + TALLOC_CTX *ctx; + BOOL ret; + + status = pdb_create_builtin_alias( BUILTIN_ALIAS_RID_ADMINS ); + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(0,("create_builtin_administrators: Failed to create Administrators\n")); + return status; + } + + /* add domain admins */ + if ((IS_DC || (lp_server_role() == ROLE_DOMAIN_MEMBER)) + && secrets_fetch_domain_sid(lp_workgroup(), &dom_admins)) + { + sid_append_rid(&dom_admins, DOMAIN_GROUP_RID_ADMINS); + status = pdb_add_aliasmem( &global_sid_Builtin_Administrators, &dom_admins ); + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(0,("create_builtin_administrators: Failed to add Domain Admins" + " Administrators\n")); + return status; + } + } + + /* add root */ + if ( (ctx = talloc_init("create_builtin_administrators")) == NULL ) { + return NT_STATUS_NO_MEMORY; + } + fstr_sprintf( root_name, "%s\\root", get_global_sam_name() ); + ret = lookup_name( ctx, root_name, 0, NULL, NULL, &root_sid, &type ); + TALLOC_FREE( ctx ); + + if ( ret ) { + status = pdb_add_aliasmem( &global_sid_Builtin_Administrators, &root_sid ); + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(0,("create_builtin_administrators: Failed to add root" + " Administrators\n")); + return status; + } + } + + return NT_STATUS_OK; +} + + +/******************************************************************* + Create a NT token for the user, expanding local aliases +*******************************************************************/ + +struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx, + const DOM_SID *user_sid, + BOOL is_guest, + int num_groupsids, + const DOM_SID *groupsids) +{ + struct nt_user_token *result = NULL; + int i; + NTSTATUS status; + gid_t gid; + + DEBUG(10, ("Create local NT token for %s\n", sid_string_static(user_sid))); + + if (!(result = TALLOC_ZERO_P(mem_ctx, NT_USER_TOKEN))) { + DEBUG(0, ("talloc failed\n")); + return NULL; + } + + /* Add the user and primary group sid */ + + if (!add_sid_to_array(result, user_sid, + &result->user_sids, &result->num_sids)) { + return NULL; + } + + /* For guest, num_groupsids may be zero. */ + if (num_groupsids) { + if (!add_sid_to_array(result, &groupsids[0], + &result->user_sids, &result->num_sids)) { + return NULL; + } + } + + /* Add in BUILTIN sids */ + + if (!add_sid_to_array(result, &global_sid_World, + &result->user_sids, &result->num_sids)) { + return NULL; + } + if (!add_sid_to_array(result, &global_sid_Network, + &result->user_sids, &result->num_sids)) { + return NULL; + } + + if (is_guest) { + if (!add_sid_to_array(result, &global_sid_Builtin_Guests, + &result->user_sids, &result->num_sids)) { + return NULL; + } + } else { + if (!add_sid_to_array(result, &global_sid_Authenticated_Users, + &result->user_sids, &result->num_sids)) { + return NULL; + } + } + + /* Now the SIDs we got from authentication. These are the ones from + * the info3 struct or from the pdb_enum_group_memberships, depending + * on who authenticated the user. + * Note that we start the for loop at "1" here, we already added the + * first group sid as primary above. */ + + for (i=1; iuser_sids, &result->num_sids)) { + return NULL; + } + } + + /* Deal with the BUILTIN\Administrators group. If the SID can + be resolved then assume that the add_aliasmem( S-1-5-32 ) + handled it. */ + + if ( !sid_to_gid( &global_sid_Builtin_Administrators, &gid ) ) { + /* We can only create a mapping if winbind is running + and the nested group functionality has been enabled */ + + if ( lp_winbind_nested_groups() && winbind_ping() ) { + become_root(); + status = create_builtin_administrators( ); + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(2,("create_local_nt_token: Failed to create BUILTIN\\Administrators group!\n")); + /* don't fail, just log the message */ + } + unbecome_root(); + } + else { + status = add_builtin_administrators( result ); + if ( !NT_STATUS_IS_OK(status) ) { + /* just log a complaint but do not fail */ + DEBUG(3,("create_local_nt_token: failed to check for local Administrators" + " membership (%s)\n", nt_errstr(status))); + } + } + } + + /* Deal with the BUILTIN\Users group. If the SID can + be resolved then assume that the add_aliasmem( S-1-5-32 ) + handled it. */ + + if ( !sid_to_gid( &global_sid_Builtin_Users, &gid ) ) { + /* We can only create a mapping if winbind is running + and the nested group functionality has been enabled */ + + if ( lp_winbind_nested_groups() && winbind_ping() ) { + become_root(); + status = create_builtin_users( ); + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(2,("create_local_nt_token: Failed to create BUILTIN\\Users group!\n")); + /* don't fail, just log the message */ + } + unbecome_root(); + } + } + + /* Deal with local groups */ + + if (lp_winbind_nested_groups()) { + + /* Now add the aliases. First the one from our local SAM */ + + status = add_aliases(get_global_sam_sid(), result); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(result); + return NULL; + } + + /* Finally the builtin ones */ + + status = add_aliases(&global_sid_Builtin, result); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(result); + return NULL; + } + } + + + get_privileges_for_sids(&result->privileges, result->user_sids, + result->num_sids); + return result; +} + +/* END */ diff --git a/source3/registry/reg_api.c b/source3/registry/reg_api.c index 7d8cd993a3..9057932538 100644 --- a/source3/registry/reg_api.c +++ b/source3/registry/reg_api.c @@ -496,3 +496,63 @@ WERROR reg_deletevalue(struct registry_key *key, const char *name) return WERR_OK; } + +/* + * Utility function to open a complete registry path including the hive + * prefix. This should become the replacement function for + * regkey_open_internal. + */ + +WERROR reg_open_path(TALLOC_CTX *mem_ctx, const char *orig_path, + uint32 desired_access, const struct nt_user_token *token, + struct registry_key **pkey) +{ + struct registry_key *hive, *key; + char *path, *p; + WERROR err; + + if (!(path = SMB_STRDUP(orig_path))) { + return WERR_NOMEM; + } + + p = strchr(path, '\\'); + + if ((p == NULL) || (p[1] == '\0')) { + /* + * No key behind the hive, just return the hive + */ + + err = reg_openhive(mem_ctx, path, desired_access, token, + &hive); + if (!W_ERROR_IS_OK(err)) { + SAFE_FREE(path); + return err; + } + SAFE_FREE(path); + *pkey = hive; + return WERR_OK; + } + + *p = '\0'; + + err = reg_openhive(mem_ctx, path, SEC_RIGHTS_ENUM_SUBKEYS, token, + &hive); + if (!W_ERROR_IS_OK(err)) { + SAFE_FREE(path); + return err; + } + + err = reg_openkey(mem_ctx, hive, p+1, desired_access, &key); + + TALLOC_FREE(hive); + SAFE_FREE(path); + + if (!W_ERROR_IS_OK(err)) { + return err; + } + + *pkey = key; + return WERR_OK; +} + +/* END */ diff --git a/source3/registry/reg_frontend.c b/source3/registry/reg_frontend.c index 2ec532dcdc..dd904f1863 100644 --- a/source3/registry/reg_frontend.c +++ b/source3/registry/reg_frontend.c @@ -45,45 +45,6 @@ REGISTRY_HOOK reg_hooks[] = { { NULL, NULL } }; - -static struct generic_mapping reg_generic_map = - { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL }; - -/******************************************************************** -********************************************************************/ - -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 ***********************************************************************/ @@ -123,231 +84,6 @@ BOOL init_registry( void ) 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 ) - return key->hook->ops->store_subkeys( key->name, subkeys ); - - return False; - -} - -/*********************************************************************** - 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; -} - -/*********************************************************************** - High level wrapper function for enumerating registry values - ***********************************************************************/ - -int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val ) -{ - 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 ); - - return ( result != -1 ) ? result : 0; - } - - return result; -} - -/*********************************************************************** - 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, - const struct nt_user_token *token ) -{ - 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 ); - } - - /* - * 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); -} - -/*********************************************************************** -***********************************************************************/ - -static int regkey_destructor(REGISTRY_KEY *key) -{ - return regdb_close(); -} - -WERROR regkey_open_onelevel( TALLOC_CTX *mem_ctx, struct registry_key *parent, - const char *name, - const struct nt_user_token *token, - uint32 access_desired, - struct registry_key **pregkey) -{ - WERROR result = WERR_OK; - struct registry_key *regkey; - REGISTRY_KEY *key; - REGSUBKEY_CTR *subkeys = NULL; - - DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name)); - - SMB_ASSERT(strchr(name, '\\') == NULL); - - if (!(regkey = TALLOC_ZERO_P(mem_ctx, struct registry_key)) || - !(regkey->token = dup_nt_token(regkey, token)) || - !(regkey->key = TALLOC_ZERO_P(regkey, REGISTRY_KEY))) { - result = WERR_NOMEM; - goto done; - } - - if ( !(W_ERROR_IS_OK(result = regdb_open())) ) { - goto done; - } - - key = regkey->key; - talloc_set_destructor(key, regkey_destructor); - - /* initialization */ - - key->type = REG_KEY_GENERIC; - - if (name[0] == '\0') { - /* - * Open a copy of the parent key - */ - if (!parent) { - result = WERR_BADFILE; - goto done; - } - key->name = talloc_strdup(key, parent->key->name); - } - else { - /* - * Normal subkey open - */ - key->name = talloc_asprintf(key, "%s%s%s", - parent ? parent->key->name : "", - parent ? "\\": "", - name); - } - - if (key->name == NULL) { - result = WERR_NOMEM; - goto done; - } - - /* Tag this as a Performance Counter Key */ - - if( StrnCaseCmp(key->name, KEY_HKPD, strlen(KEY_HKPD)) == 0 ) - key->type = REG_KEY_HKPD; - - /* Look up the table of registry I/O operations */ - - if ( !(key->hook = reghook_cache_find( key->name )) ) { - DEBUG(0,("reg_open_onelevel: Failed to assigned a " - "REGISTRY_HOOK to [%s]\n", key->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( key, REGSUBKEY_CTR )) ) { - result = WERR_NOMEM; - goto done; - } - - if ( fetch_reg_keys( key, subkeys ) == -1 ) { - result = WERR_BADFILE; - goto done; - } - - TALLOC_FREE( subkeys ); - - if ( !regkey_access_check( key, access_desired, &key->access_granted, - token ) ) { - result = WERR_ACCESS_DENIED; - goto done; - } - - *pregkey = regkey; - result = WERR_OK; - -done: - if ( !W_ERROR_IS_OK(result) ) { - TALLOC_FREE(regkey); - } - - return result; -} - WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY **regkey, const char *path, const struct nt_user_token *token, @@ -366,29 +102,6 @@ WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY **regkey, return WERR_OK; } -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) { @@ -399,65 +112,6 @@ WERROR regkey_set_secdesc(REGISTRY_KEY *key, return WERR_ACCESS_DENIED; } - -/* - * Utility function to open a complete registry path including the hive - * prefix. This should become the replacement function for - * regkey_open_internal. - */ - -WERROR reg_open_path(TALLOC_CTX *mem_ctx, const char *orig_path, - uint32 desired_access, const struct nt_user_token *token, - struct registry_key **pkey) -{ - struct registry_key *hive, *key; - char *path, *p; - WERROR err; - - if (!(path = SMB_STRDUP(orig_path))) { - return WERR_NOMEM; - } - - p = strchr(path, '\\'); - - if ((p == NULL) || (p[1] == '\0')) { - /* - * No key behind the hive, just return the hive - */ - - err = reg_openhive(mem_ctx, path, desired_access, token, - &hive); - if (!W_ERROR_IS_OK(err)) { - SAFE_FREE(path); - return err; - } - SAFE_FREE(path); - *pkey = hive; - return WERR_OK; - } - - *p = '\0'; - - err = reg_openhive(mem_ctx, path, SEC_RIGHTS_ENUM_SUBKEYS, token, - &hive); - if (!W_ERROR_IS_OK(err)) { - SAFE_FREE(path); - return err; - } - - err = reg_openkey(mem_ctx, hive, p+1, desired_access, &key); - - TALLOC_FREE(hive); - SAFE_FREE(path); - - if (!W_ERROR_IS_OK(err)) { - return err; - } - - *pkey = key; - return WERR_OK; -} - /* * Utility function to create a registry key without opening the hive * before. Assumes the hive already exists. diff --git a/source3/registry/reg_frontend_hilvl.c b/source3/registry/reg_frontend_hilvl.c new file mode 100644 index 0000000000..72441535b5 --- /dev/null +++ b/source3/registry/reg_frontend_hilvl.c @@ -0,0 +1,315 @@ +/* + * Unix SMB/CIFS implementation. + * Virtual Windows Registry Layer + * Copyright (C) Gerald Carter 2002-2005 + * Copyright (C) Michael Adam 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. + */ + +/* + * Implementation of registry frontend view functions. + * Functions moved from reg_frontend.c to minimize linker deps. + */ + +#include "includes.h" + + +static struct generic_mapping reg_generic_map = + { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL }; + +/******************************************************************** +********************************************************************/ + +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; +} + +/*********************************************************************** + 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 ) + return key->hook->ops->store_subkeys( key->name, subkeys ); + + return False; + +} + +/*********************************************************************** + 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; +} + +/*********************************************************************** + High level wrapper function for enumerating registry values + ***********************************************************************/ + +int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val ) +{ + 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 ); + + return ( result != -1 ) ? result : 0; + } + + return result; +} + +/*********************************************************************** + 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, + const struct nt_user_token *token ) +{ + 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 ); + } + + /* + * 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); +} + +/*********************************************************************** +***********************************************************************/ + +static int regkey_destructor(REGISTRY_KEY *key) +{ + return regdb_close(); +} + +WERROR regkey_open_onelevel( TALLOC_CTX *mem_ctx, struct registry_key *parent, + const char *name, + const struct nt_user_token *token, + uint32 access_desired, + struct registry_key **pregkey) +{ + WERROR result = WERR_OK; + struct registry_key *regkey; + REGISTRY_KEY *key; + REGSUBKEY_CTR *subkeys = NULL; + + DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name)); + + SMB_ASSERT(strchr(name, '\\') == NULL); + + if (!(regkey = TALLOC_ZERO_P(mem_ctx, struct registry_key)) || + !(regkey->token = dup_nt_token(regkey, token)) || + !(regkey->key = TALLOC_ZERO_P(regkey, REGISTRY_KEY))) { + result = WERR_NOMEM; + goto done; + } + + if ( !(W_ERROR_IS_OK(result = regdb_open())) ) { + goto done; + } + + key = regkey->key; + talloc_set_destructor(key, regkey_destructor); + + /* initialization */ + + key->type = REG_KEY_GENERIC; + + if (name[0] == '\0') { + /* + * Open a copy of the parent key + */ + if (!parent) { + result = WERR_BADFILE; + goto done; + } + key->name = talloc_strdup(key, parent->key->name); + } + else { + /* + * Normal subkey open + */ + key->name = talloc_asprintf(key, "%s%s%s", + parent ? parent->key->name : "", + parent ? "\\": "", + name); + } + + if (key->name == NULL) { + result = WERR_NOMEM; + goto done; + } + + /* Tag this as a Performance Counter Key */ + + if( StrnCaseCmp(key->name, KEY_HKPD, strlen(KEY_HKPD)) == 0 ) + key->type = REG_KEY_HKPD; + + /* Look up the table of registry I/O operations */ + + if ( !(key->hook = reghook_cache_find( key->name )) ) { + DEBUG(0,("reg_open_onelevel: Failed to assigned a " + "REGISTRY_HOOK to [%s]\n", key->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( key, REGSUBKEY_CTR )) ) { + result = WERR_NOMEM; + goto done; + } + + if ( fetch_reg_keys( key, subkeys ) == -1 ) { + result = WERR_BADFILE; + goto done; + } + + TALLOC_FREE( subkeys ); + + if ( !regkey_access_check( key, access_desired, &key->access_granted, + token ) ) { + result = WERR_ACCESS_DENIED; + goto done; + } + + *pregkey = regkey; + result = WERR_OK; + +done: + if ( !W_ERROR_IS_OK(result) ) { + TALLOC_FREE(regkey); + } + + return result; +} + +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; +} + + +/* END */ diff --git a/source3/utils/net.c b/source3/utils/net.c index 5a9b7d31ec..fc26be8609 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -85,6 +85,7 @@ int opt_attrs = 0; int opt_timestamps = 0; const char *opt_exclude = NULL; const char *opt_destination = NULL; +BOOL opt_testmode = False; BOOL opt_have_ip = False; struct in_addr opt_dest_ip; @@ -871,6 +872,7 @@ static struct functable net_func[] = { {"STATUS", net_status}, {"USERSHARE", net_usershare}, {"USERSIDLIST", net_usersidlist}, + {"CONF", net_conf}, #ifdef WITH_FAKE_KASERVER {"AFS", net_afs}, #endif @@ -912,6 +914,7 @@ static struct functable net_func[] = { {"machine-pass",'P', POPT_ARG_NONE, &opt_machine_pass}, {"myworkgroup", 'W', POPT_ARG_STRING, &opt_workgroup}, {"verbose", 'v', POPT_ARG_NONE, &opt_verbose}, + {"test", 'T', POPT_ARG_NONE, &opt_testmode}, /* Options for 'net groupmap set' */ {"local", 'L', POPT_ARG_NONE, &opt_localgroup}, {"domain", 'D', POPT_ARG_NONE, &opt_domaingroup}, diff --git a/source3/utils/net.h b/source3/utils/net.h index 6d4468e934..3739abdad7 100644 --- a/source3/utils/net.h +++ b/source3/utils/net.h @@ -114,6 +114,7 @@ extern int opt_attrs; extern int opt_timestamps; extern const char *opt_exclude; extern const char *opt_destination; +extern BOOL opt_testmode; extern BOOL opt_have_ip; extern struct in_addr opt_dest_ip; diff --git a/source3/utils/net_conf.c b/source3/utils/net_conf.c new file mode 100644 index 0000000000..7d8849a99a --- /dev/null +++ b/source3/utils/net_conf.c @@ -0,0 +1,1118 @@ +/* + * Samba Unix/Linux SMB client library + * Distributed SMB/CIFS Server Management Utility + * Local configuration interface + * Copyright (C) Michael Adam 2007 + * + * 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. + */ + +/* + * This currently only an interface to the configuration + * stored inside the samba registry. In the future there + * might be support for other configuration backends as well. + */ + +/* + * TODO: + * + * - check uid 0 for write operations + * - check for valid parameter names and types (loadparm...) ??? + * - check for correctness of shares (service_ok) ? + * - refactor to use _internal functions for pieces of code + * + */ + +#include "includes.h" +#include "utils/net.h" + +extern REGISTRY_OPS smbconf_reg_ops; + +/* + * usage functions + */ + +static int net_conf_list_usage(int argc, const char **argv) +{ + d_printf("USAGE: net conf list\n"); + return -1; +} + +static int net_conf_import_usage(int argc, const char**argv) +{ + d_printf("USAGE: net conf import [--test|-T] []\n" + "\t[--test|-T] testmode - do not act, just print " + "what would be done\n" + "\t only import service , " + "ignore the rest\n"); + return -1; +} + +static int net_conf_listshares_usage(int argc, const char **argv) +{ + d_printf("USAGE: net conf listshares\n"); + return -1; +} + +static int net_conf_showshare_usage(int argc, const char **argv) +{ + d_printf("USAGE: net conf showshare \n"); + return -1; +} + +static int net_conf_addshare_usage(int argc, const char **argv) +{ + d_printf("USAGE: net conf addshare " + "[writeable={y|N} [guest_ok={y|N} []]\n" + "\t the new share name.\n" + "\t the path on the filesystem to export.\n" + "\twriteable={y|N} set \"writeable to \"yes\" or " + "\"no\" (default) on this share.\n" + "\tguest_ok={y|N} set \"guest ok\" to \"yes\" or " + "\"no\" (default) on this share.\n" + "\t optional comment for the new share.\n"); + return -1; +} + +static int net_conf_delshare_usage(int argc, const char **argv) +{ + d_printf("USAGE: net conf delshare \n"); + return -1; +} + +static int net_conf_setparm_usage(int argc, const char **argv) +{ + d_printf("USAGE: net conf setparm
\n" + "\t(Supported types are 'dword' and 'sz' by now.)\n"); + return -1; +} + +static int net_conf_getparm_usage(int argc, const char **argv) +{ + d_printf("USAGE: net conf getparm
\n"); + return -1; +} + +static int net_conf_delparm_usage(int argc, const char **argv) +{ + d_printf("USAGE: net conf delparm
\n"); + return -1; +} + + +/* + * Helper functions + */ + +static char *format_value(TALLOC_CTX *mem_ctx, struct registry_value *value) +{ + char *result = NULL; + + /* what if mem_ctx = NULL? */ + + switch (value->type) { + case REG_DWORD: + result = talloc_asprintf(mem_ctx, "%d", value->v.dword); + break; + case REG_SZ: + case REG_EXPAND_SZ: + result = talloc_asprintf(mem_ctx, "%s", value->v.sz.str); + break; + case REG_MULTI_SZ: { + uint32 j; + for (j = 0; j < value->v.multi_sz.num_strings; j++) { + result = talloc_asprintf(mem_ctx, "\"%s\" ", + value->v.multi_sz.strings[j]); + } + break; + } + case REG_BINARY: + result = talloc_asprintf(mem_ctx, "binary (%d bytes)", + (int)value->v.binary.length); + break; + default: + result = talloc_asprintf(mem_ctx, ""); + break; + } + return result; +} + +/* + * add a value to a key. + */ +static WERROR reg_setvalue_internal(struct registry_key *key, + const char *valname, + const char *valtype, + const char *valstr) +{ + struct registry_value val; + WERROR werr = WERR_OK; + + ZERO_STRUCT(val); + + if (strequal(valtype, "dword")) { + val.type = REG_DWORD; + val.v.dword = strtoul(valstr, NULL, 10); + } + else if (strequal(valtype, "sz")) { + val.type = REG_SZ; + val.v.sz.str = CONST_DISCARD(char *, valstr); + val.v.sz.len = strlen(valstr) + 1; + } + else { + d_fprintf(stderr, "Sorry, only value types DWORD and SZ implementd currently for setting values.\n"); + goto done; + } + + werr = reg_setvalue(key, valname, &val); + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, + "Error adding value '%s' to " + "key '%s': %s\n", + valname, key->key->name, dos_errstr(werr)); + } + +done: + return werr; +} + +/* + * Open a subkey of KEY_SMBCONF (i.e a service) + * - variant without error output (q = quiet)- + */ +static WERROR smbconf_open_path_q(TALLOC_CTX *ctx, const char *subkeyname, + uint32 desired_access, + struct registry_key **key) +{ + WERROR werr = WERR_OK; + char *path = NULL; + + if (subkeyname == NULL) { + path = talloc_strdup(ctx, KEY_SMBCONF); + } + else { + path = talloc_asprintf(ctx, "%s\\%s", KEY_SMBCONF, subkeyname); + } + + werr = reg_open_path(ctx, path, desired_access, + get_root_nt_token(), key); + + TALLOC_FREE(path); + return werr; +} + +/* + * Open a subkey of KEY_SMBCONF (i.e a service) + * - variant with error output - + */ +static WERROR smbconf_open_path(TALLOC_CTX *ctx, const char *subkeyname, + uint32 desired_access, + struct registry_key **key) +{ + WERROR werr = WERR_OK; + + werr = smbconf_open_path_q(ctx, subkeyname, desired_access, key); + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, "Error opening registry path '%s\\%s': %s\n", + KEY_SMBCONF, + (subkeyname == NULL) ? "" : subkeyname, + dos_errstr(werr)); + } + + return werr; +} + +/* + * open the base key KEY_SMBCONF + */ +static WERROR smbconf_open_basepath(TALLOC_CTX *ctx, uint32 desired_access, + struct registry_key **key) +{ + return smbconf_open_path(ctx, NULL, desired_access, key); +} + +/* + * delete a subkey of KEY_SMBCONF + */ +static WERROR reg_delkey_internal(TALLOC_CTX *ctx, const char *keyname) +{ + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + + werr = smbconf_open_basepath(ctx, REG_KEY_WRITE, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = reg_deletekey(key, keyname); + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, "Error deleting registry key %s\\%s: %s\n", + KEY_SMBCONF, keyname, dos_errstr(werr)); + } + +done: + TALLOC_FREE(key); + return werr; +} + +/* + * create a subkey of KEY_SMBCONF + */ +static WERROR reg_createkey_internal(TALLOC_CTX *ctx, + const char * subkeyname, + struct registry_key **newkey) +{ + WERROR werr = WERR_OK; + struct registry_key *create_parent = NULL; + TALLOC_CTX *create_ctx; + enum winreg_CreateAction action = REG_ACTION_NONE; + + /* create a new talloc ctx for creation. it will hold + * the intermediate parent key (SMBCONF) for creation + * and will be destroyed when leaving this function... */ + if (!(create_ctx = talloc_new(ctx))) { + werr = WERR_NOMEM; + goto done; + } + + werr = smbconf_open_basepath(create_ctx, REG_KEY_WRITE, &create_parent); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = reg_createkey(ctx, create_parent, subkeyname, + REG_KEY_WRITE, newkey, &action); + if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) { + d_fprintf(stderr, "Key '%s' already exists.\n", subkeyname); + werr = WERR_ALREADY_EXISTS; + } + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, "Error creating key %s: %s\n", + subkeyname, dos_errstr(werr)); + } + +done: + TALLOC_FREE(create_ctx); + return werr; +} + +/* + * check if a subkey of KEY_SMBCONF of a given name exists + */ +static BOOL smbconf_key_exists(TALLOC_CTX *ctx, const char *subkeyname) +{ + BOOL ret = False; + WERROR werr = WERR_OK; + TALLOC_CTX *mem_ctx; + struct registry_key *key; + + if (!(mem_ctx = talloc_new(ctx))) { + d_fprintf(stderr, "ERROR: Out of memory...!\n"); + goto done; + } + + werr = smbconf_open_path_q(mem_ctx, subkeyname, REG_KEY_READ, &key); + if (W_ERROR_IS_OK(werr)) { + ret = True; + } + +done: + TALLOC_FREE(mem_ctx); + return ret; +} + +static BOOL smbconf_value_exists(TALLOC_CTX *ctx, struct registry_key *key, + const char *param) +{ + BOOL ret = False; + WERROR werr = WERR_OK; + struct registry_value *value = NULL; + + werr = reg_queryvalue(ctx, key, param, &value); + if (W_ERROR_IS_OK(werr)) { + ret = True; + } + + TALLOC_FREE(value); + return ret; +} + +static WERROR list_values(TALLOC_CTX *ctx, struct registry_key *key) +{ + WERROR werr = WERR_OK; + uint32 idx = 0; + struct registry_value *valvalue = NULL; + char *valname = NULL; + + for (idx = 0; + W_ERROR_IS_OK(werr = reg_enumvalue(ctx, key, idx, &valname, + &valvalue)); + idx++) + { + d_printf("\t%s = %s\n", valname, format_value(ctx, valvalue)); + } + if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) { + d_fprintf(stderr, "Error enumerating values: %s\n", + dos_errstr(werr)); + goto done; + } + werr = WERR_OK; + +done: + return werr; +} + +static int import_process_service(TALLOC_CTX *ctx, + struct share_params *share) +{ + int ret = -1; + struct parm_struct *parm; + int pnum = 0; + const char *servicename; + struct registry_key *key; + WERROR werr; + const char *valtype = NULL; + char *valstr = NULL; + + servicename = (share->service == GLOBAL_SECTION_SNUM)? + GLOBAL_NAME : lp_servicename(share->service); + + if (opt_testmode) { + d_printf("[%s]\n", servicename); + } + else { + if (smbconf_key_exists(ctx, servicename)) { + werr = reg_delkey_internal(ctx, servicename); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + } + werr = reg_createkey_internal(ctx, servicename, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + } + + while ((parm = lp_next_parameter(share->service, &pnum, 0))) + { + void *ptr = parm->ptr; + int i = 0; + + if ((share->service < 0 && parm->p_class == P_LOCAL) + && !(parm->flags & FLAG_GLOBAL)) + continue; + + if (parm->p_class == P_LOCAL && share->service >= 0) { + ptr = lp_local_ptr(share->service, ptr); + } + + valtype = "sz"; + + switch (parm->type) { + case P_CHAR: + valstr = talloc_asprintf(ctx, "%c", *(char *)ptr); + break; + case P_STRING: + case P_USTRING: + valstr = talloc_asprintf(ctx, "%s", *(char **)ptr); + break; + case P_GSTRING: + case P_UGSTRING: + valstr = talloc_asprintf(ctx, "%s", (char *)ptr); + break; + case P_BOOL: + valstr = talloc_asprintf(ctx, "%s", + BOOLSTR(*(BOOL *)ptr)); + break; + case P_BOOLREV: + valstr = talloc_asprintf(ctx, "%s", + BOOLSTR(!*(BOOL *)ptr)); + break; + case P_ENUM: + for (i = 0; parm->enum_list[i].name; i++) { + if (*(int *)ptr == + parm->enum_list[i].value) + { + valstr = talloc_asprintf(ctx, "%s", + parm->enum_list[i].name); + break; + } + } + break; + case P_OCTAL: + talloc_asprintf(ctx, "%s", octal_string(*(int *)ptr)); + break; + case P_LIST: + valstr = talloc_strdup(ctx, ""); + if ((char ***)ptr && *(char ***)ptr) { + char **list = *(char ***)ptr; + for (; *list; list++) { + /* surround strings with whitespace + * in double quotes */ + if (strchr_m(*list, ' ')) + { + valstr = talloc_asprintf_append( + valstr, "\"%s\"%s", + *list, + ((*(list+1))?", ":"")); + } + else { + valstr = talloc_asprintf_append( + valstr, "%s%s", *list, + ((*(list+1))?", ":"")); + } + } + } + break; + case P_INTEGER: + valtype = "dword"; + talloc_asprintf(ctx, "%d", *(int *)ptr); + break; + case P_SEP: + break; + default: + valstr = talloc_asprintf(ctx, "\n"); + break; + } + + if (parm->type != P_SEP) { + if (opt_testmode) { + d_printf("\t%s = %s\n", parm->label, valstr); + } + else { + werr = reg_setvalue_internal(key, parm->label, + valtype, valstr); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + } + } + } + + if (opt_testmode) { + d_printf("\n"); + } + + ret = 0; +done: + return ret; +} + + +/* + * the conf functions + */ + +int net_conf_list(int argc, const char **argv) +{ + WERROR werr = WERR_OK; + int ret = -1; + TALLOC_CTX *ctx; + struct registry_key *base_key = NULL; + struct registry_key *sub_key = NULL; + uint32 idx_key = 0; + char *subkey_name = NULL; + + ctx = talloc_init("list"); + + if (argc != 0) { + net_conf_list_usage(argc, argv); + goto done; + } + + werr = smbconf_open_basepath(ctx, REG_KEY_READ, &base_key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (smbconf_key_exists(ctx, GLOBAL_NAME)) { + werr = reg_openkey(ctx, base_key, GLOBAL_NAME, + REG_KEY_READ, &sub_key); + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, "Error opening subkey '%s' : %s\n", + subkey_name, dos_errstr(werr)); + goto done; + } + d_printf("[%s]\n", GLOBAL_NAME); + if (!W_ERROR_IS_OK(list_values(ctx, sub_key))) { + goto done; + } + d_printf("\n"); + } + + for (idx_key = 0; + W_ERROR_IS_OK(werr = reg_enumkey(ctx, base_key, idx_key, + &subkey_name, NULL)); + idx_key++) + { + if (strequal(subkey_name, GLOBAL_NAME)) { + continue; + } + d_printf("[%s]\n", subkey_name); + + werr = reg_openkey(ctx, base_key, subkey_name, + REG_KEY_READ, &sub_key); + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, + "Error opening subkey '%s': %s\n", + subkey_name, dos_errstr(werr)); + goto done; + } + if (!W_ERROR_IS_OK(list_values(ctx, sub_key))) { + goto done; + } + d_printf("\n"); + } + if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) { + d_fprintf(stderr, "Error enumerating subkeys: %s\n", + dos_errstr(werr)); + goto done; + } + + ret = 0; + +done: + TALLOC_FREE(ctx); + return ret; +} + +int net_conf_import(int argc, const char **argv) +{ + int ret = -1; + const char *filename = NULL; + const char *servicename = NULL; + BOOL service_found = False; + TALLOC_CTX *ctx; + struct share_iterator *shares; + struct share_params *share; + struct share_params global_share = { GLOBAL_SECTION_SNUM }; + + ctx = talloc_init("net_conf_import"); + + switch (argc) { + case 0: + default: + net_conf_import_usage(argc, argv); + goto done; + case 2: + servicename = argv[1]; + case 1: + filename = argv[0]; + break; + } + + DEBUG(3,("net_conf_import: reading configuration from file %s.\n", + filename)); + + /* TODO: check for existence and readability */ + + if (!lp_load(filename, + False, /* global_only */ + True, /* save_defaults */ + False, /* add_ipc */ + True)) /* initialize_globals */ + { + d_fprintf(stderr, "Error parsing configuration file.\n"); + goto done; + } + + if (opt_testmode) { + d_printf("\nTEST MODE - would import the following configuration:\n\n"); + } + + if ((servicename == NULL) || strequal(servicename, GLOBAL_NAME)) { + service_found = True; + if (import_process_service(ctx, &global_share) != 0) { + goto done; + } + } + + if (service_found && (servicename != NULL)) { + ret = 0; + goto done; + } + + if (!(shares = share_list_all(ctx))) { + d_fprintf(stderr, "Could not list shares...\n"); + goto done; + } + while ((share = next_share(shares)) != NULL) { + if ((servicename == NULL) + || strequal(servicename, lp_servicename(share->service))) + { + service_found = True; + if (import_process_service(ctx, share)!= 0) { + goto done; + } + } + } + + if ((servicename != NULL) && !service_found) { + d_printf("Share %s not found in file %s\n", + servicename, filename); + goto done; + + } + + ret = 0; + +done: + TALLOC_FREE(ctx); + return ret; +} + +int net_conf_listshares(int argc, const char **argv) +{ + WERROR werr = WERR_OK; + int ret = -1; + struct registry_key *key; + uint32 idx = 0; + char *subkey_name = NULL; + TALLOC_CTX *ctx; + + ctx = talloc_init("listshares"); + + if (argc != 0) { + net_conf_listshares_usage(argc, argv); + goto done; + } + + werr = smbconf_open_basepath(ctx, SEC_RIGHTS_ENUM_SUBKEYS, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + for (idx = 0; + W_ERROR_IS_OK(werr = reg_enumkey(ctx, key, idx, + &subkey_name, NULL)); + idx++) + { + d_printf("%s\n", subkey_name); + } + if (! W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) { + d_fprintf(stderr, "Error enumerating subkeys: %s\n", + dos_errstr(werr)); + goto done; + } + + ret = 0; + +done: + TALLOC_FREE(ctx); + return ret; +} + +int net_conf_showshare(int argc, const char **argv) +{ + int ret = -1; + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + TALLOC_CTX *ctx; + + ctx = talloc_init("showshare"); + + if (argc != 1) { + net_conf_showshare_usage(argc, argv); + goto done; + } + + werr = smbconf_open_path(ctx, argv[0], REG_KEY_READ, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + d_printf("[%s]\n", argv[0]); + + if (!W_ERROR_IS_OK(list_values(ctx, key))) { + goto done; + } + + ret = 0; + +done: + TALLOC_FREE(ctx); + return ret; +} + +int net_conf_addshare(int argc, const char **argv) +{ + int ret = -1; + WERROR werr = WERR_OK; + struct registry_key *newkey = NULL; + char *sharename = NULL; + const char *path = NULL; + const char *comment = NULL; + const char *guest_ok = "no"; + const char *writeable = "no"; + SMB_STRUCT_STAT sbuf; + + switch (argc) { + case 0: + case 1: + default: + net_conf_addshare_usage(argc, argv); + goto done; + case 5: + comment = argv[4]; + case 4: + if (!strnequal(argv[3], "guest_ok=", 9)) { + net_conf_addshare_usage(argc, argv); + goto done; + } + switch (argv[3][9]) { + case 'y': + case 'Y': + guest_ok = "yes"; + break; + case 'n': + case 'N': + guest_ok = "no"; + break; + default: + net_conf_addshare_usage(argc, argv); + goto done; + } + case 3: + if (!strnequal(argv[2], "writeable=", 10)) { + net_conf_addshare_usage(argc, argv); + goto done; + } + switch (argv[2][10]) { + case 'y': + case 'Y': + writeable = "yes"; + break; + case 'n': + case 'N': + writeable = "no"; + break; + default: + net_conf_addshare_usage(argc, argv); + goto done; + } + + case 2: + path = argv[1]; + sharename = strdup_lower(argv[0]); + break; + } + + /* + * validate arguments + */ + + /* validate share name */ + + if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, + strlen(sharename))) + { + d_fprintf(stderr, "ERROR: share name %s contains " + "invalid characters (any of %s)\n", + sharename, INVALID_SHARENAME_CHARS); + goto done; + } + + if (getpwnam(sharename)) { + d_fprintf(stderr, "ERROR: share name %s is already a valid " + "system user name.\n", sharename); + goto done; + } + + if (strequal(sharename, GLOBAL_NAME)) { + d_fprintf(stderr, + "ERROR: 'global' is not a valid share name.\n"); + goto done; + } + + /* validate path */ + + if (path[0] != '/') { + d_fprintf(stderr, + "Error: path '%s' is not an absolute path.\n", + path); + goto done; + } + + if (sys_stat(path, &sbuf) != 0) { + d_fprintf(stderr, + "ERROR: cannot stat path '%s' to ensure " + "this is a directory.\n" + "Error was '%s'.\n", + path, strerror(errno)); + goto done; + } + + if (!S_ISDIR(sbuf.st_mode)) { + d_fprintf(stderr, + "ERROR: path '%s' is not a directory.\n", + path); + goto done; + } + + /* + * create the share + */ + + werr = reg_createkey_internal(NULL, argv[0], &newkey); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + /* add config params as values */ + + werr = reg_setvalue_internal(newkey, "path", "sz", path); + if (!W_ERROR_IS_OK(werr)) + goto done; + + if (comment != NULL) { + werr = reg_setvalue_internal(newkey, "comment", "sz", comment); + if (!W_ERROR_IS_OK(werr)) + goto done; + } + + werr = reg_setvalue_internal(newkey, "guest ok", "sz", guest_ok); + if (!W_ERROR_IS_OK(werr)) + goto done; + + werr = reg_setvalue_internal(newkey, "writeable", "sz", writeable); + if (!W_ERROR_IS_OK(werr)) + goto done; + + ret = 0; + +done: + TALLOC_FREE(newkey); + SAFE_FREE(sharename); + return ret; +} + +int net_conf_delshare(int argc, const char **argv) +{ + int ret = -1; + const char *sharename = NULL; + + if (argc != 1) { + net_conf_delshare_usage(argc, argv); + goto done; + } + sharename = argv[0]; + + if (W_ERROR_IS_OK(reg_delkey_internal(NULL, sharename))) { + ret = 0; + } +done: + return ret; +} + +static int net_conf_setparm(int argc, const char **argv) +{ + int ret = -1; + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + char *service = NULL; + char *param = NULL; + char *type = NULL; + const char *value_str = NULL; + TALLOC_CTX *ctx; + + ctx = talloc_init("setparm"); + + if (argc != 4) { + net_conf_setparm_usage(argc, argv); + goto done; + } + service = strdup_lower(argv[0]); + param = strdup_lower(argv[1]); + type = strdup_lower(argv[2]); + value_str = argv[3]; + + if (!smbconf_key_exists(ctx, service)) { + werr = reg_createkey_internal(ctx, service, &key); + } + else { + werr = smbconf_open_path(ctx, service, REG_KEY_READ, &key); + } + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = reg_setvalue_internal(key, param, type, value_str); + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, "Error setting value '%s': %s\n", + param, dos_errstr(werr)); + goto done; + } + + + ret = 0; + +done: + SAFE_FREE(service); + TALLOC_FREE(ctx); + return ret; +} + +static int net_conf_getparm(int argc, const char **argv) +{ + int ret = -1; + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + char *service = NULL; + char *param = NULL; + struct registry_value *value = NULL; + TALLOC_CTX *ctx; + + ctx = talloc_init("getparm"); + + if (argc != 2) { + net_conf_getparm_usage(argc, argv); + goto done; + } + service = strdup_lower(argv[0]); + param = strdup_lower(argv[1]); + + if (!smbconf_key_exists(ctx, service)) { + d_fprintf(stderr, + "ERROR: given service '%s' does not exist.\n", + service); + goto done; + } + + werr = smbconf_open_path(ctx, service, REG_KEY_READ, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = reg_queryvalue(ctx, key, param, &value); + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, "Error querying value '%s': %s.\n", + param, dos_errstr(werr)); + goto done; + } + + d_printf("%s\n", format_value(ctx, value)); + + ret = 0; +done: + SAFE_FREE(service); + SAFE_FREE(param); + TALLOC_FREE(ctx); + return ret; +} + +static int net_conf_delparm(int argc, const char **argv) +{ + int ret = -1; + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + char *service = NULL; + char *param = NULL; + TALLOC_CTX *ctx; + + ctx = talloc_init("delparm"); + + if (argc != 2) { + net_conf_delparm_usage(argc, argv); + goto done; + } + service = strdup_lower(argv[0]); + param = strdup_lower(argv[1]); + + if (!smbconf_key_exists(ctx, service)) { + d_fprintf(stderr, + "Error: given service '%s' does not exist.\n", + service); + goto done; + } + + werr = smbconf_open_path(ctx, service, REG_KEY_READ, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (!smbconf_value_exists(ctx, key, param)) { + d_fprintf(stderr, + "Error: given parameter '%s' is not set.\n", + param); + goto done; + } + werr = reg_deletevalue(key, param); + if (!W_ERROR_IS_OK(werr)) { + d_fprintf(stderr, "Error deleting value '%s': %s.\n", + param, dos_errstr(werr)); + goto done; + } + + ret = 0; + +done: + return ret; +} + +/* + * Entry-point for all the CONF functions. + */ + +int net_conf(int argc, const char **argv) +{ + int ret = -1; + int saved_errno = 0; + struct functable2 func[] = { + {"list", net_conf_list, + "Dump the complete configuration in smb.conf like format."}, + {"import", net_conf_import, + "Import configuration from file in smb.conf format."}, + {"listshares", net_conf_listshares, + "List the registry shares."}, + {"showshare", net_conf_showshare, + "Show the definition of a registry share."}, + {"addshare", net_conf_addshare, + "Create a new registry share."}, + {"delshare", net_conf_delshare, + "Delete a registry share."}, + {"setparm", net_conf_setparm, + "Store a parameter."}, + {"getparm", net_conf_getparm, + "Retrieve the value of a parameter."}, + {"delparm", net_conf_delparm, + "Delete a parameter."}, + {NULL, NULL, NULL} + }; + + REGISTRY_HOOK smbconf_reg_hook = {KEY_SMBCONF, &smbconf_reg_ops}; + + if (!regdb_init()) { + saved_errno = errno; + d_fprintf(stderr, "Can't open the registry"); + if (saved_errno) { + d_fprintf(stderr, ": %s\n", strerror(saved_errno)); + } + else { + d_fprintf(stderr, "!\n"); + } + goto done; + } + reghook_cache_init(); + reghook_cache_add(&smbconf_reg_hook); + + ret = net_run_function2(argc, argv, "net conf", func); + + regdb_close(); + +done: + return ret; +} + +/* END */ -- cgit