From 7f642e51670bc38a4ef782a363936850bc2b0ba9 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 22 Apr 2021 06:38:23 -0700 Subject: Move dutil into libs/dutil --- src/libs/dutil/WixToolset.DUtil/srputil.cpp | 252 ++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 src/libs/dutil/WixToolset.DUtil/srputil.cpp (limited to 'src/libs/dutil/WixToolset.DUtil/srputil.cpp') diff --git a/src/libs/dutil/WixToolset.DUtil/srputil.cpp b/src/libs/dutil/WixToolset.DUtil/srputil.cpp new file mode 100644 index 00000000..e44536cc --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/srputil.cpp @@ -0,0 +1,252 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// Exit macros +#define SrpExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) +#define SrpExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) +#define SrpExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) +#define SrpExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) +#define SrpExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) +#define SrpExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) +#define SrpExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_SRPUTIL, p, x, e, s, __VA_ARGS__) +#define SrpExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_SRPUTIL, p, x, s, __VA_ARGS__) +#define SrpExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_SRPUTIL, p, x, e, s, __VA_ARGS__) +#define SrpExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_SRPUTIL, p, x, s, __VA_ARGS__) +#define SrpExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_SRPUTIL, e, x, s, __VA_ARGS__) +#define SrpExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_SRPUTIL, g, x, s, __VA_ARGS__) + + +typedef BOOL (WINAPI *PFN_SETRESTOREPTW)( + __in PRESTOREPOINTINFOW pRestorePtSpec, + __out PSTATEMGRSTATUS pSMgrStatus + ); + +static PFN_SETRESTOREPTW vpfnSRSetRestorePointW = NULL; +static HMODULE vhSrClientDll = NULL; + + +static HRESULT InitializeComSecurity(); + + +DAPI_(HRESULT) SrpInitialize( + __in BOOL fInitializeComSecurity + ) +{ + HRESULT hr = S_OK; + + hr = LoadSystemLibrary(L"srclient.dll", &vhSrClientDll); + if (FAILED(hr)) + { + ExitFunction1(hr = E_NOTIMPL); + } + + vpfnSRSetRestorePointW = reinterpret_cast(::GetProcAddress(vhSrClientDll, "SRSetRestorePointW")); + SrpExitOnNullWithLastError(vpfnSRSetRestorePointW, hr, "Failed to find set restore point proc address."); + + // If allowed, initialize COM security to enable NetworkService, + // LocalService and System to make callbacks to the process + // calling System Restore. This is required for any process + // that calls SRSetRestorePoint. + if (fInitializeComSecurity) + { + hr = InitializeComSecurity(); + SrpExitOnFailure(hr, "Failed to initialize security for COM to talk to system restore."); + } + +LExit: + if (FAILED(hr) && vhSrClientDll) + { + SrpUninitialize(); + } + + return hr; +} + +DAPI_(void) SrpUninitialize() +{ + if (vhSrClientDll) + { + ::FreeLibrary(vhSrClientDll); + vhSrClientDll = NULL; + vpfnSRSetRestorePointW = NULL; + } +} + +DAPI_(HRESULT) SrpCreateRestorePoint( + __in_z LPCWSTR wzApplicationName, + __in SRP_ACTION action + ) +{ + HRESULT hr = S_OK; + RESTOREPOINTINFOW restorePoint = { }; + STATEMGRSTATUS status = { }; + + if (!vpfnSRSetRestorePointW) + { + ExitFunction1(hr = E_NOTIMPL); + } + + restorePoint.dwEventType = BEGIN_SYSTEM_CHANGE; + restorePoint.dwRestorePtType = (SRP_ACTION_INSTALL == action) ? APPLICATION_INSTALL : (SRP_ACTION_UNINSTALL == action) ? APPLICATION_UNINSTALL : MODIFY_SETTINGS; + ::StringCbCopyW(restorePoint.szDescription, sizeof(restorePoint.szDescription), wzApplicationName); + + if (!vpfnSRSetRestorePointW(&restorePoint, &status)) + { + SrpExitOnWin32Error(status.nStatus, hr, "Failed to create system restore point."); + } + +LExit: + return hr; +} + + +// internal functions. + +static HRESULT InitializeComSecurity() +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + SECURITY_DESCRIPTOR sd = {0}; + EXPLICIT_ACCESS ea[5] = {0}; + ACL* pAcl = NULL; + ULONGLONG rgSidBA[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; + ULONGLONG rgSidLS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; + ULONGLONG rgSidNS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; + ULONGLONG rgSidPS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; + ULONGLONG rgSidSY[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; + DWORD cbSid = 0; + + // Create the security descriptor explicitly as follows because + // CoInitializeSecurity() will not accept the relative security descriptors + // returned by ConvertStringSecurityDescriptorToSecurityDescriptor(). + // + // The result is a security descriptor that is equivalent to the following + // security descriptor definition language (SDDL) string: + // + // O:BAG:BAD:(A;;0x1;;;LS)(A;;0x1;;;NS)(A;;0x1;;;PS)(A;;0x1;;;SY)(A;;0x1;;;BA) + // + + // Initialize the security descriptor. + if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) + { + SrpExitWithLastError(hr, "Failed to initialize security descriptor for system restore."); + } + + // Create an administrator group security identifier (SID). + cbSid = sizeof(rgSidBA); + if (!::CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, rgSidBA, &cbSid)) + { + SrpExitWithLastError(hr, "Failed to create administrator SID for system restore."); + } + + // Create a local service security identifier (SID). + cbSid = sizeof(rgSidLS); + if (!::CreateWellKnownSid(WinLocalServiceSid, NULL, rgSidLS, &cbSid)) + { + SrpExitWithLastError(hr, "Failed to create local service SID for system restore."); + } + + // Create a network service security identifier (SID). + cbSid = sizeof(rgSidNS); + if (!::CreateWellKnownSid(WinNetworkServiceSid, NULL, rgSidNS, &cbSid)) + { + SrpExitWithLastError(hr, "Failed to create network service SID for system restore."); + } + + // Create a personal account security identifier (SID). + cbSid = sizeof(rgSidPS); + if (!::CreateWellKnownSid(WinSelfSid, NULL, rgSidPS, &cbSid)) + { + SrpExitWithLastError(hr, "Failed to create self SID for system restore."); + } + + // Create a local service security identifier (SID). + cbSid = sizeof(rgSidSY); + if (!::CreateWellKnownSid(WinLocalSystemSid, NULL, rgSidSY, &cbSid)) + { + SrpExitWithLastError(hr, "Failed to create local system SID for system restore."); + } + + // Setup the access control entries (ACE) for COM. COM_RIGHTS_EXECUTE and + // COM_RIGHTS_EXECUTE_LOCAL are the minimum access rights required. + ea[0].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; + ea[0].grfAccessMode = SET_ACCESS; + ea[0].grfInheritance = NO_INHERITANCE; + ea[0].Trustee.pMultipleTrustee = NULL; + ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP; + ea[0].Trustee.ptstrName = (LPTSTR)rgSidBA; + + ea[1].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; + ea[1].grfAccessMode = SET_ACCESS; + ea[1].grfInheritance = NO_INHERITANCE; + ea[1].Trustee.pMultipleTrustee = NULL; + ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; + ea[1].Trustee.ptstrName = (LPTSTR)rgSidLS; + + ea[2].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; + ea[2].grfAccessMode = SET_ACCESS; + ea[2].grfInheritance = NO_INHERITANCE; + ea[2].Trustee.pMultipleTrustee = NULL; + ea[2].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[2].Trustee.TrusteeType = TRUSTEE_IS_GROUP; + ea[2].Trustee.ptstrName = (LPTSTR)rgSidNS; + + ea[3].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; + ea[3].grfAccessMode = SET_ACCESS; + ea[3].grfInheritance = NO_INHERITANCE; + ea[3].Trustee.pMultipleTrustee = NULL; + ea[3].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[3].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[3].Trustee.TrusteeType = TRUSTEE_IS_GROUP; + ea[3].Trustee.ptstrName = (LPTSTR)rgSidPS; + + ea[4].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; + ea[4].grfAccessMode = SET_ACCESS; + ea[4].grfInheritance = NO_INHERITANCE; + ea[4].Trustee.pMultipleTrustee = NULL; + ea[4].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[4].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[4].Trustee.TrusteeType = TRUSTEE_IS_GROUP; + ea[4].Trustee.ptstrName = (LPTSTR)rgSidSY; + + // Create an access control list (ACL) using this ACE list. + er = ::SetEntriesInAcl(countof(ea), ea, NULL, &pAcl); + SrpExitOnWin32Error(er, hr, "Failed to create ACL for system restore."); + + // Set the security descriptor owner to Administrators. + if (!::SetSecurityDescriptorOwner(&sd, rgSidBA, FALSE)) + { + SrpExitWithLastError(hr, "Failed to set administrators owner for system restore."); + } + + // Set the security descriptor group to Administrators. + if (!::SetSecurityDescriptorGroup(&sd, rgSidBA, FALSE)) + { + SrpExitWithLastError(hr, "Failed to set administrators group access for system restore."); + } + + // Set the discretionary access control list (DACL) to the ACL. + if (!::SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) + { + SrpExitWithLastError(hr, "Failed to set DACL for system restore."); + } + + // Note that an explicit security descriptor is being passed in. + hr= ::CoInitializeSecurity(&sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL, NULL); + SrpExitOnFailure(hr, "Failed to initialize COM security for system restore."); + +LExit: + if (pAcl) + { + ::LocalFree(pAcl); + } + + return hr; +} -- cgit v1.2.3-55-g6feb