From 96565db5f66f791968ed354fc8f39464ff0a7e5a Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 31 Jan 2011 16:40:33 +0100 Subject: s3-services: Migrated svcctl registry functions to winreg. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a bigger commit. It moves the relevant function to svc_winreg_glue. We need to use them in the same commit else we have problems with prototypes in proto.h. Signed-off-by: Günther Deschner --- source3/Makefile.in | 3 +- source3/include/proto.h | 12 -- source3/rpc_server/srv_ntsvcs_nt.c | 6 +- source3/rpc_server/srv_svcctl_nt.c | 93 +++++++--- source3/services/svc_winreg_glue.c | 364 +++++++++++++++++++++++++++++++++++++ source3/services/svc_winreg_glue.h | 57 ++++++ 6 files changed, 495 insertions(+), 40 deletions(-) create mode 100644 source3/services/svc_winreg_glue.c create mode 100644 source3/services/svc_winreg_glue.h diff --git a/source3/Makefile.in b/source3/Makefile.in index ad7690771b..92687f0ba2 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -688,7 +688,8 @@ RPC_WKSSVC_OBJ = librpc/gen_ndr/srv_wkssvc.o \ RPC_SVCCTL_OBJ = rpc_server/srv_svcctl_nt.o \ librpc/gen_ndr/srv_svcctl.o \ - services/svc_spoolss.o services/svc_rcinit.o services/services_db.o \ + services/svc_winreg_glue.o \ + services/svc_spoolss.o services/svc_rcinit.o \ services/svc_netlogon.o services/svc_winreg.o \ services/svc_wins.o diff --git a/source3/include/proto.h b/source3/include/proto.h index 94cd0a9867..4094df7769 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -4412,18 +4412,6 @@ bool init_service_op_table( void ); /* The following definitions come from rpcclient/rpcclient.c */ -/* The following definitions come from services/services_db.c */ - -void svcctl_init_keys( void ); -struct security_descriptor *svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, struct security_token *token ); -bool svcctl_set_secdesc(const char *name, struct security_descriptor *sec_desc, - struct security_token *token); -const char *svcctl_get_string_value(TALLOC_CTX *ctx, const char *key_name, - const char *value_name, - struct security_token *token); -const char *svcctl_lookup_dispname(TALLOC_CTX *ctx, const char *name, struct security_token *token ); -const char *svcctl_lookup_description(TALLOC_CTX *ctx, const char *name, struct security_token *token ); - /* The following definitions come from services/svc_netlogon.c */ diff --git a/source3/rpc_server/srv_ntsvcs_nt.c b/source3/rpc_server/srv_ntsvcs_nt.c index a948b86c21..4933cb31a5 100644 --- a/source3/rpc_server/srv_ntsvcs_nt.c +++ b/source3/rpc_server/srv_ntsvcs_nt.c @@ -21,6 +21,7 @@ #include "includes.h" #include "../librpc/gen_ndr/srv_ntsvcs.h" +#include "services/svc_winreg_glue.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV @@ -142,7 +143,10 @@ WERROR _PNP_GetDeviceRegProp(struct pipes_struct *p, mem_ctx = talloc_stackframe(); - result = svcctl_lookup_dispname(mem_ctx, ptr, p->server_info->ptok); + result = svcctl_lookup_dispname(mem_ctx, + p->msg_ctx, + p->server_info, + ptr); if (result == NULL) { return WERR_GENERAL_FAILURE; } diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c index 2a7ef81645..cc6cf84eb6 100644 --- a/source3/rpc_server/srv_svcctl_nt.c +++ b/source3/rpc_server/srv_svcctl_nt.c @@ -24,9 +24,10 @@ #include "includes.h" #include "../librpc/gen_ndr/srv_svcctl.h" -#include "services/services.h" #include "../libcli/security/security.h" #include "../librpc/gen_ndr/ndr_security.h" +#include "services/services.h" +#include "services/svc_winreg_glue.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV @@ -301,11 +302,19 @@ WERROR _svcctl_OpenServiceW(struct pipes_struct *p, if ( !find_service_info_by_hnd( p, r->in.scmanager_handle) ) return WERR_BADFID; - /* perform access checks. Use the root token in order to ensure that we - retrieve the security descriptor */ - - if ( !(sec_desc = svcctl_get_secdesc( p->mem_ctx, service, get_root_nt_token() )) ) + /* + * Perform access checks. Use the system server_info in order to ensure + * that we retrieve the security descriptor + */ + sec_desc = svcctl_get_secdesc(p->mem_ctx, + p->msg_ctx, + get_server_info_system(), + service); + if (sec_desc == NULL) { + DEBUG(0, ("_svcctl_OpenServiceW: Failed to get a valid security " + "descriptor")); return WERR_NOMEM; + } se_map_generic( &r->in.access_mask, &svc_generic_map ); status = svcctl_access_check( sec_desc, p->server_info->ptok, @@ -349,8 +358,10 @@ WERROR _svcctl_GetServiceDisplayNameW(struct pipes_struct *p, service = r->in.service_name; - display_name = svcctl_lookup_dispname(p->mem_ctx, service, - p->server_info->ptok); + display_name = svcctl_lookup_dispname(p->mem_ctx, + p->msg_ctx, + p->server_info, + service); if (!display_name) { display_name = ""; } @@ -386,7 +397,10 @@ WERROR _svcctl_QueryServiceStatus(struct pipes_struct *p, /******************************************************************** ********************************************************************/ -static int enumerate_status( TALLOC_CTX *ctx, struct ENUM_SERVICE_STATUSW **status, struct security_token *token ) +static int enumerate_status(TALLOC_CTX *ctx, + struct messaging_context *msg_ctx, + struct auth_serversupplied_info *server_info, + struct ENUM_SERVICE_STATUSW **status) { int num_services = 0; int i; @@ -405,7 +419,10 @@ static int enumerate_status( TALLOC_CTX *ctx, struct ENUM_SERVICE_STATUSW **stat for ( i=0; iservice_status( svcctl_ops[i].name, &st[i].status ); @@ -429,7 +446,6 @@ WERROR _svcctl_EnumServicesStatusW(struct pipes_struct *p, size_t buffer_size = 0; WERROR result = WERR_OK; SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - struct security_token *token = p->server_info->ptok; DATA_BLOB blob = data_blob_null; /* perform access checks */ @@ -441,7 +457,10 @@ WERROR _svcctl_EnumServicesStatusW(struct pipes_struct *p, return WERR_ACCESS_DENIED; } - num_services = enumerate_status( p->mem_ctx, &services, token ); + num_services = enumerate_status(p->mem_ctx, + p->msg_ctx, + p->server_info, + &services); if (num_services == -1 ) { return WERR_NOMEM; } @@ -639,23 +658,36 @@ WERROR _svcctl_QueryServiceStatusEx(struct pipes_struct *p, /******************************************************************** ********************************************************************/ -static WERROR fill_svc_config( TALLOC_CTX *ctx, const char *name, - struct QUERY_SERVICE_CONFIG *config, - struct security_token *token ) +static WERROR fill_svc_config(TALLOC_CTX *ctx, + struct messaging_context *msg_ctx, + struct auth_serversupplied_info *server_info, + const char *name, + struct QUERY_SERVICE_CONFIG *config) { TALLOC_CTX *mem_ctx = talloc_stackframe(); const char *result = NULL; /* now fill in the individual values */ - config->displayname = svcctl_lookup_dispname(mem_ctx, name, token); + config->displayname = svcctl_lookup_dispname(mem_ctx, + msg_ctx, + server_info, + name); - result = svcctl_get_string_value(mem_ctx, name, "ObjectName", token); + result = svcctl_get_string_value(mem_ctx, + msg_ctx, + server_info, + name, + "ObjectName"); if (result != NULL) { config->startname = result; } - result = svcctl_get_string_value(mem_ctx, name, "ImagePath", token); + result = svcctl_get_string_value(mem_ctx, + msg_ctx, + server_info, + name, + "ImagePath"); if (result != NULL) { config->executablepath = result; } @@ -708,8 +740,11 @@ WERROR _svcctl_QueryServiceConfigW(struct pipes_struct *p, *r->out.needed = r->in.offered; - wresult = fill_svc_config( p->mem_ctx, info->name, r->out.query, - p->server_info->ptok); + wresult = fill_svc_config(p->mem_ctx, + p->msg_ctx, + p->server_info, + info->name, + r->out.query); if ( !W_ERROR_IS_OK(wresult) ) return wresult; @@ -754,8 +789,10 @@ WERROR _svcctl_QueryServiceConfig2W(struct pipes_struct *p, enum ndr_err_code ndr_err; DATA_BLOB blob; - description = svcctl_lookup_description( - p->mem_ctx, info->name, p->server_info->ptok); + description = svcctl_lookup_description(p->mem_ctx, + p->msg_ctx, + p->server_info, + info->name); desc_buf.description = description; @@ -874,10 +911,14 @@ WERROR _svcctl_QueryServiceObjectSecurity(struct pipes_struct *p, if ( (r->in.security_flags & SECINFO_DACL) != SECINFO_DACL ) return WERR_INVALID_PARAM; - /* lookup the security descriptor and marshall it up for a reply */ - - if ( !(sec_desc = svcctl_get_secdesc( p->mem_ctx, info->name, get_root_nt_token() )) ) - return WERR_NOMEM; + /* Lookup the security descriptor and marshall it up for a reply */ + sec_desc = svcctl_get_secdesc(p->mem_ctx, + p->msg_ctx, + get_server_info_system(), + info->name); + if (sec_desc == NULL) { + return WERR_NOMEM; + } *r->out.needed = ndr_size_security_descriptor(sec_desc, 0); @@ -949,7 +990,7 @@ WERROR _svcctl_SetServiceObjectSecurity(struct pipes_struct *p, /* store the new SD */ - if (!svcctl_set_secdesc(info->name, sec_desc, p->server_info->ptok)) + if (!svcctl_set_secdesc(p->msg_ctx, p->server_info, info->name, sec_desc)) return WERR_ACCESS_DENIED; return WERR_OK; diff --git a/source3/services/svc_winreg_glue.c b/source3/services/svc_winreg_glue.c new file mode 100644 index 0000000000..2ab9914bcc --- /dev/null +++ b/source3/services/svc_winreg_glue.c @@ -0,0 +1,364 @@ +/* + * Unix SMB/CIFS implementation. + * + * SVC winreg glue + * + * Copyright (c) 2005 Marcin Krzysztof Porwit + * Copyright (c) 2005 Gerald (Jerry) Carter + * Copyright (c) 2011 Andreas Schneider + * + * 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 3 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, see . + */ + +#include "includes.h" +#include "services/services.h" +#include "services/svc_winreg_glue.h" +#include "rpc_client/cli_winreg_int.h" +#include "rpc_client/cli_winreg.h" +#include "../librpc/gen_ndr/ndr_winreg_c.h" +#include "../libcli/security/security.h" + +#define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services" + +struct security_descriptor* svcctl_gen_service_sd(TALLOC_CTX *mem_ctx) +{ + struct security_descriptor *sd = NULL; + struct security_acl *theacl = NULL; + struct security_ace ace[4]; + size_t sd_size; + size_t i = 0; + + /* Basic access for everyone */ + init_sec_ace(&ace[i++], &global_sid_World, + SEC_ACE_TYPE_ACCESS_ALLOWED, SERVICE_READ_ACCESS, 0); + + init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, + SEC_ACE_TYPE_ACCESS_ALLOWED, SERVICE_EXECUTE_ACCESS, 0); + + init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, + SEC_ACE_TYPE_ACCESS_ALLOWED, SERVICE_ALL_ACCESS, 0); + init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, + SEC_ACE_TYPE_ACCESS_ALLOWED, SERVICE_ALL_ACCESS, 0); + + /* Create the security descriptor */ + theacl = make_sec_acl(mem_ctx, + NT4_ACL_REVISION, + i, + ace); + if (theacl == NULL) { + return NULL; + } + + sd = make_sec_desc(mem_ctx, + SECURITY_DESCRIPTOR_REVISION_1, + SEC_DESC_SELF_RELATIVE, + NULL, + NULL, + NULL, + theacl, + &sd_size); + if (sd == NULL) { + return NULL; + } + + return sd; +} + +struct security_descriptor *svcctl_get_secdesc(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *name) +{ + struct dcerpc_binding_handle *h = NULL; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + struct security_descriptor *sd = NULL; + char *key = NULL; + NTSTATUS status; + WERROR result = WERR_OK; + + key = talloc_asprintf(mem_ctx, + "%s\\%s\\Security", + TOP_LEVEL_SERVICES_KEY, name); + if (key == NULL) { + return NULL; + } + + status = dcerpc_winreg_int_hklm_openkey(mem_ctx, + server_info, + msg_ctx, + &h, + key, + false, + access_mask, + &hive_hnd, + &key_hnd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_set_secdesc: Could not open %s - %s\n", + key, nt_errstr(status))); + return NULL; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_set_secdesc: Could not open %s - %s\n", + key, win_errstr(result))); + return NULL; + } + + status = dcerpc_winreg_query_sd(mem_ctx, + h, + &key_hnd, + "Security", + &sd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_get_secdesc: error getting value 'Security': " + "%s\n", nt_errstr(status))); + return NULL; + } + if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + goto fallback_to_default_sd; + } else if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_get_secdesc: error getting value 'Security': " + "%s\n", win_errstr(result))); + return NULL; + } + + goto done; + +fallback_to_default_sd: + DEBUG(6, ("svcctl_get_secdesc: constructing default secdesc for " + "service [%s]\n", name)); + sd = svcctl_gen_service_sd(mem_ctx); + +done: + return sd; +} + +bool svcctl_set_secdesc(struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *name, + struct security_descriptor *sd) +{ + struct dcerpc_binding_handle *h = NULL; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + char *key = NULL; + bool ok = false; + TALLOC_CTX *tmp_ctx; + NTSTATUS status; + WERROR result = WERR_OK; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return false; + } + + key = talloc_asprintf(tmp_ctx, "%s\\%s", TOP_LEVEL_SERVICES_KEY, name); + if (key == NULL) { + goto done; + } + + status = dcerpc_winreg_int_hklm_openkey(tmp_ctx, + server_info, + msg_ctx, + &h, + key, + false, + access_mask, + &hive_hnd, + &key_hnd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_set_secdesc: Could not open %s - %s\n", + key, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_set_secdesc: Could not open %s - %s\n", + key, win_errstr(result))); + goto done; + } + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + + { + enum winreg_CreateAction action = REG_ACTION_NONE; + struct winreg_String wkey; + struct winreg_String wkeyclass; + + wkey.name = talloc_asprintf(tmp_ctx, "%s\\Security", key); + if (wkey.name == NULL) { + result = WERR_NOMEM; + goto done; + } + + ZERO_STRUCT(wkeyclass); + wkeyclass.name = ""; + + status = dcerpc_winreg_CreateKey(h, + tmp_ctx, + &hive_hnd, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + &key_hnd, + &action, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_set_secdesc: Could not create key %s: %s\n", + wkey.name, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_set_secdesc: Could not create key %s: %s\n", + wkey.name, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_sd(tmp_ctx, + h, + &key_hnd, + "Security", + sd, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + ok = true; + +done: + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + + talloc_free(tmp_ctx); + return ok; +} + +const char *svcctl_get_string_value(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *key_name, + const char *value_name) +{ + struct dcerpc_binding_handle *h = NULL; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + const char *data = NULL; + char *path = NULL; + TALLOC_CTX *tmp_ctx; + NTSTATUS status; + WERROR result = WERR_OK; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return NULL; + } + + path = talloc_asprintf(tmp_ctx, "%s\\%s", + TOP_LEVEL_SERVICES_KEY, key_name); + if (path == NULL) { + goto done; + } + + status = dcerpc_winreg_int_hklm_openkey(tmp_ctx, + server_info, + msg_ctx, + &h, + path, + false, + access_mask, + &hive_hnd, + &key_hnd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_get_string_value: Could not open %s - %s\n", + path, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_get_string_value: Could not open %s - %s\n", + path, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_query_sz(mem_ctx, + h, + &key_hnd, + value_name, + &data, + &result); + +done: + talloc_free(tmp_ctx); + return data; +} + +/******************************************************************** +********************************************************************/ + +const char *svcctl_lookup_dispname(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *name) +{ + const char *display_name = NULL; + + display_name = svcctl_get_string_value(mem_ctx, + msg_ctx, + server_info, + name, + "DisplayName"); + + if (display_name == NULL) { + display_name = talloc_strdup(mem_ctx, name); + } + + return display_name; +} + +/******************************************************************** +********************************************************************/ + +const char *svcctl_lookup_description(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *name) +{ + const char *description = NULL; + + description = svcctl_get_string_value(mem_ctx, + msg_ctx, + server_info, + name, + "Description"); + + if (description == NULL) { + description = talloc_strdup(mem_ctx, "Unix Service"); + } + + return description; +} + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/services/svc_winreg_glue.h b/source3/services/svc_winreg_glue.h new file mode 100644 index 0000000000..f2f036e725 --- /dev/null +++ b/source3/services/svc_winreg_glue.h @@ -0,0 +1,57 @@ +/* + * Unix SMB/CIFS implementation. + * + * SVC winreg glue + * + * Copyright (c) 2005 Marcin Krzysztof Porwit + * Copyright (c) 2005 Gerald (Jerry) Carter + * Copyright (c) 2011 Andreas Schneider + * + * 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 3 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, see . + */ + +#ifndef SVC_WINREG_GLUE_H +#define SVC_WINREG_GLUE_H + +struct security_descriptor* svcctl_gen_service_sd(TALLOC_CTX *mem_ctx); + +struct security_descriptor *svcctl_get_secdesc(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *name); + +bool svcctl_set_secdesc(struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *name, + struct security_descriptor *sd); + +const char *svcctl_get_string_value(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *key_name, + const char *value_name); + +const char *svcctl_lookup_dispname(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *name); + +const char *svcctl_lookup_description(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct auth_serversupplied_info *server_info, + const char *name); + +#endif /* SVC_WINREG_GLUE_H */ + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ -- cgit