/* * 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; } WERROR svcctl_get_secdesc(struct messaging_context *msg_ctx, const struct auth_session_info *session_info, const char *name, TALLOC_CTX *mem_ctx, struct security_descriptor **psd) { 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 WERR_NOT_ENOUGH_MEMORY; } status = dcerpc_winreg_int_hklm_openkey(mem_ctx, session_info, msg_ctx, &h, key, false, access_mask, &hive_hnd, &key_hnd, &result); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("svcctl_set_secdesc: Could not open %s - %s\n", key, nt_errstr(status))); return WERR_INTERNAL_ERROR; } if (!W_ERROR_IS_OK(result)) { DEBUG(2, ("svcctl_set_secdesc: Could not open %s - %s\n", key, win_errstr(result))); return result; } status = dcerpc_winreg_query_sd(mem_ctx, h, &key_hnd, "Security", &sd, &result); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("svcctl_get_secdesc: error getting value 'Security': " "%s\n", nt_errstr(status))); return WERR_INTERNAL_ERROR; } if (W_ERROR_EQUAL(result, WERR_FILE_NOT_FOUND)) { goto fallback_to_default_sd; } else if (!W_ERROR_IS_OK(result)) { DEBUG(2, ("svcctl_get_secdesc: error getting value 'Security': " "%s\n", win_errstr(result))); return result; } 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); if (sd == NULL) { return WERR_NOT_ENOUGH_MEMORY; } done: *psd = sd; return WERR_OK; } bool svcctl_set_secdesc(struct messaging_context *msg_ctx, const struct auth_session_info *session_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; struct policy_handle key_hnd = { 0, }; 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, session_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 = { 0, }; struct winreg_String wkeyclass; wkey.name = talloc_asprintf(tmp_ctx, "%s\\Security", key); if (wkey.name == NULL) { result = WERR_NOT_ENOUGH_MEMORY; 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(2, ("svcctl_set_secdesc: Could not create key %s: %s\n", wkey.name, nt_errstr(status))); goto done; } if (!W_ERROR_IS_OK(result)) { DEBUG(2, ("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_session_info *session_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, session_info, msg_ctx, &h, path, false, access_mask, &hive_hnd, &key_hnd, &result); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("svcctl_get_string_value: Could not open %s - %s\n", path, nt_errstr(status))); goto done; } if (!W_ERROR_IS_OK(result)) { DEBUG(2, ("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_session_info *session_info, const char *name) { const char *display_name = NULL; display_name = svcctl_get_string_value(mem_ctx, msg_ctx, session_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_session_info *session_info, const char *name) { const char *description = NULL; description = svcctl_get_string_value(mem_ctx, msg_ctx, session_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: */