| 1 | // 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. |
| 2 | |
| 3 | #include "precomp.h" |
| 4 | |
| 5 | |
| 6 | // Exit macros |
| 7 | #define SrpExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) |
| 8 | #define SrpExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) |
| 9 | #define SrpExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) |
| 10 | #define SrpExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) |
| 11 | #define SrpExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) |
| 12 | #define SrpExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_SRPUTIL, x, s, __VA_ARGS__) |
| 13 | #define SrpExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_SRPUTIL, p, x, e, s, __VA_ARGS__) |
| 14 | #define SrpExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_SRPUTIL, p, x, s, __VA_ARGS__) |
| 15 | #define SrpExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_SRPUTIL, p, x, e, s, __VA_ARGS__) |
| 16 | #define SrpExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_SRPUTIL, p, x, s, __VA_ARGS__) |
| 17 | #define SrpExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_SRPUTIL, e, x, s, __VA_ARGS__) |
| 18 | #define SrpExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_SRPUTIL, g, x, s, __VA_ARGS__) |
| 19 | |
| 20 | |
| 21 | typedef BOOL (WINAPI *PFN_SETRESTOREPTW)( |
| 22 | __in PRESTOREPOINTINFOW pRestorePtSpec, |
| 23 | __out PSTATEMGRSTATUS pSMgrStatus |
| 24 | ); |
| 25 | |
| 26 | static PFN_SETRESTOREPTW vpfnSRSetRestorePointW = NULL; |
| 27 | static HMODULE vhSrClientDll = NULL; |
| 28 | |
| 29 | |
| 30 | static HRESULT InitializeComSecurity(); |
| 31 | |
| 32 | |
| 33 | DAPI_(HRESULT) SrpInitialize( |
| 34 | __in BOOL fInitializeComSecurity |
| 35 | ) |
| 36 | { |
| 37 | HRESULT hr = S_OK; |
| 38 | |
| 39 | hr = LoadSystemLibrary(L"srclient.dll", &vhSrClientDll); |
| 40 | if (FAILED(hr)) |
| 41 | { |
| 42 | ExitFunction1(hr = E_NOTIMPL); |
| 43 | } |
| 44 | |
| 45 | vpfnSRSetRestorePointW = reinterpret_cast<PFN_SETRESTOREPTW>(::GetProcAddress(vhSrClientDll, "SRSetRestorePointW")); |
| 46 | SrpExitOnNullWithLastError(vpfnSRSetRestorePointW, hr, "Failed to find set restore point proc address."); |
| 47 | |
| 48 | // If allowed, initialize COM security to enable NetworkService, |
| 49 | // LocalService and System to make callbacks to the process |
| 50 | // calling System Restore. This is required for any process |
| 51 | // that calls SRSetRestorePoint. |
| 52 | if (fInitializeComSecurity) |
| 53 | { |
| 54 | hr = InitializeComSecurity(); |
| 55 | SrpExitOnFailure(hr, "Failed to initialize security for COM to talk to system restore."); |
| 56 | } |
| 57 | |
| 58 | LExit: |
| 59 | if (FAILED(hr) && vhSrClientDll) |
| 60 | { |
| 61 | SrpUninitialize(); |
| 62 | } |
| 63 | |
| 64 | return hr; |
| 65 | } |
| 66 | |
| 67 | DAPI_(void) SrpUninitialize() |
| 68 | { |
| 69 | if (vhSrClientDll) |
| 70 | { |
| 71 | ::FreeLibrary(vhSrClientDll); |
| 72 | vhSrClientDll = NULL; |
| 73 | vpfnSRSetRestorePointW = NULL; |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | DAPI_(HRESULT) SrpCreateRestorePoint( |
| 78 | __in_z LPCWSTR wzApplicationName, |
| 79 | __in SRP_ACTION action |
| 80 | ) |
| 81 | { |
| 82 | HRESULT hr = S_OK; |
| 83 | RESTOREPOINTINFOW restorePoint = { }; |
| 84 | STATEMGRSTATUS status = { }; |
| 85 | |
| 86 | if (!vpfnSRSetRestorePointW) |
| 87 | { |
| 88 | ExitFunction1(hr = E_NOTIMPL); |
| 89 | } |
| 90 | |
| 91 | restorePoint.dwEventType = BEGIN_SYSTEM_CHANGE; |
| 92 | restorePoint.dwRestorePtType = (SRP_ACTION_INSTALL == action) ? APPLICATION_INSTALL : (SRP_ACTION_UNINSTALL == action) ? APPLICATION_UNINSTALL : MODIFY_SETTINGS; |
| 93 | ::StringCbCopyW(restorePoint.szDescription, sizeof(restorePoint.szDescription), wzApplicationName); |
| 94 | |
| 95 | if (!vpfnSRSetRestorePointW(&restorePoint, &status)) |
| 96 | { |
| 97 | SrpExitOnWin32Error(status.nStatus, hr, "Failed to create system restore point."); |
| 98 | } |
| 99 | |
| 100 | LExit: |
| 101 | return hr; |
| 102 | } |
| 103 | |
| 104 | |
| 105 | // internal functions. |
| 106 | |
| 107 | static HRESULT InitializeComSecurity() |
| 108 | { |
| 109 | HRESULT hr = S_OK; |
| 110 | DWORD er = ERROR_SUCCESS; |
| 111 | SECURITY_DESCRIPTOR sd = {0}; |
| 112 | EXPLICIT_ACCESS ea[5] = {0}; |
| 113 | ACL* pAcl = NULL; |
| 114 | ULONGLONG rgSidBA[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; |
| 115 | ULONGLONG rgSidLS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; |
| 116 | ULONGLONG rgSidNS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; |
| 117 | ULONGLONG rgSidPS[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; |
| 118 | ULONGLONG rgSidSY[(SECURITY_MAX_SID_SIZE+sizeof(ULONGLONG)-1)/sizeof(ULONGLONG)]={0}; |
| 119 | DWORD cbSid = 0; |
| 120 | |
| 121 | // Create the security descriptor explicitly as follows because |
| 122 | // CoInitializeSecurity() will not accept the relative security descriptors |
| 123 | // returned by ConvertStringSecurityDescriptorToSecurityDescriptor(). |
| 124 | // |
| 125 | // The result is a security descriptor that is equivalent to the following |
| 126 | // security descriptor definition language (SDDL) string: |
| 127 | // |
| 128 | // O:BAG:BAD:(A;;0x1;;;LS)(A;;0x1;;;NS)(A;;0x1;;;PS)(A;;0x1;;;SY)(A;;0x1;;;BA) |
| 129 | // |
| 130 | |
| 131 | // Initialize the security descriptor. |
| 132 | if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) |
| 133 | { |
| 134 | SrpExitWithLastError(hr, "Failed to initialize security descriptor for system restore."); |
| 135 | } |
| 136 | |
| 137 | // Create an administrator group security identifier (SID). |
| 138 | cbSid = sizeof(rgSidBA); |
| 139 | if (!::CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, rgSidBA, &cbSid)) |
| 140 | { |
| 141 | SrpExitWithLastError(hr, "Failed to create administrator SID for system restore."); |
| 142 | } |
| 143 | |
| 144 | // Create a local service security identifier (SID). |
| 145 | cbSid = sizeof(rgSidLS); |
| 146 | if (!::CreateWellKnownSid(WinLocalServiceSid, NULL, rgSidLS, &cbSid)) |
| 147 | { |
| 148 | SrpExitWithLastError(hr, "Failed to create local service SID for system restore."); |
| 149 | } |
| 150 | |
| 151 | // Create a network service security identifier (SID). |
| 152 | cbSid = sizeof(rgSidNS); |
| 153 | if (!::CreateWellKnownSid(WinNetworkServiceSid, NULL, rgSidNS, &cbSid)) |
| 154 | { |
| 155 | SrpExitWithLastError(hr, "Failed to create network service SID for system restore."); |
| 156 | } |
| 157 | |
| 158 | // Create a personal account security identifier (SID). |
| 159 | cbSid = sizeof(rgSidPS); |
| 160 | if (!::CreateWellKnownSid(WinSelfSid, NULL, rgSidPS, &cbSid)) |
| 161 | { |
| 162 | SrpExitWithLastError(hr, "Failed to create self SID for system restore."); |
| 163 | } |
| 164 | |
| 165 | // Create a local service security identifier (SID). |
| 166 | cbSid = sizeof(rgSidSY); |
| 167 | if (!::CreateWellKnownSid(WinLocalSystemSid, NULL, rgSidSY, &cbSid)) |
| 168 | { |
| 169 | SrpExitWithLastError(hr, "Failed to create local system SID for system restore."); |
| 170 | } |
| 171 | |
| 172 | // Setup the access control entries (ACE) for COM. COM_RIGHTS_EXECUTE and |
| 173 | // COM_RIGHTS_EXECUTE_LOCAL are the minimum access rights required. |
| 174 | ea[0].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; |
| 175 | ea[0].grfAccessMode = SET_ACCESS; |
| 176 | ea[0].grfInheritance = NO_INHERITANCE; |
| 177 | ea[0].Trustee.pMultipleTrustee = NULL; |
| 178 | ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; |
| 179 | ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| 180 | ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP; |
| 181 | ea[0].Trustee.ptstrName = (LPTSTR)rgSidBA; |
| 182 | |
| 183 | ea[1].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; |
| 184 | ea[1].grfAccessMode = SET_ACCESS; |
| 185 | ea[1].grfInheritance = NO_INHERITANCE; |
| 186 | ea[1].Trustee.pMultipleTrustee = NULL; |
| 187 | ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; |
| 188 | ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| 189 | ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; |
| 190 | ea[1].Trustee.ptstrName = (LPTSTR)rgSidLS; |
| 191 | |
| 192 | ea[2].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; |
| 193 | ea[2].grfAccessMode = SET_ACCESS; |
| 194 | ea[2].grfInheritance = NO_INHERITANCE; |
| 195 | ea[2].Trustee.pMultipleTrustee = NULL; |
| 196 | ea[2].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; |
| 197 | ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| 198 | ea[2].Trustee.TrusteeType = TRUSTEE_IS_GROUP; |
| 199 | ea[2].Trustee.ptstrName = (LPTSTR)rgSidNS; |
| 200 | |
| 201 | ea[3].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; |
| 202 | ea[3].grfAccessMode = SET_ACCESS; |
| 203 | ea[3].grfInheritance = NO_INHERITANCE; |
| 204 | ea[3].Trustee.pMultipleTrustee = NULL; |
| 205 | ea[3].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; |
| 206 | ea[3].Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| 207 | ea[3].Trustee.TrusteeType = TRUSTEE_IS_GROUP; |
| 208 | ea[3].Trustee.ptstrName = (LPTSTR)rgSidPS; |
| 209 | |
| 210 | ea[4].grfAccessPermissions = COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL; |
| 211 | ea[4].grfAccessMode = SET_ACCESS; |
| 212 | ea[4].grfInheritance = NO_INHERITANCE; |
| 213 | ea[4].Trustee.pMultipleTrustee = NULL; |
| 214 | ea[4].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; |
| 215 | ea[4].Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| 216 | ea[4].Trustee.TrusteeType = TRUSTEE_IS_GROUP; |
| 217 | ea[4].Trustee.ptstrName = (LPTSTR)rgSidSY; |
| 218 | |
| 219 | // Create an access control list (ACL) using this ACE list. |
| 220 | er = ::SetEntriesInAcl(countof(ea), ea, NULL, &pAcl); |
| 221 | SrpExitOnWin32Error(er, hr, "Failed to create ACL for system restore."); |
| 222 | |
| 223 | // Set the security descriptor owner to Administrators. |
| 224 | if (!::SetSecurityDescriptorOwner(&sd, rgSidBA, FALSE)) |
| 225 | { |
| 226 | SrpExitWithLastError(hr, "Failed to set administrators owner for system restore."); |
| 227 | } |
| 228 | |
| 229 | // Set the security descriptor group to Administrators. |
| 230 | if (!::SetSecurityDescriptorGroup(&sd, rgSidBA, FALSE)) |
| 231 | { |
| 232 | SrpExitWithLastError(hr, "Failed to set administrators group access for system restore."); |
| 233 | } |
| 234 | |
| 235 | // Set the discretionary access control list (DACL) to the ACL. |
| 236 | if (!::SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) |
| 237 | { |
| 238 | SrpExitWithLastError(hr, "Failed to set DACL for system restore."); |
| 239 | } |
| 240 | |
| 241 | // Note that an explicit security descriptor is being passed in. |
| 242 | 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); |
| 243 | SrpExitOnFailure(hr, "Failed to initialize COM security for system restore."); |
| 244 | |
| 245 | LExit: |
| 246 | if (pAcl) |
| 247 | { |
| 248 | ::LocalFree(pAcl); |
| 249 | } |
| 250 | |
| 251 | return hr; |
| 252 | } |