aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/srputil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/srputil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/srputil.cpp252
1 files changed, 252 insertions, 0 deletions
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 @@
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
21typedef BOOL (WINAPI *PFN_SETRESTOREPTW)(
22 __in PRESTOREPOINTINFOW pRestorePtSpec,
23 __out PSTATEMGRSTATUS pSMgrStatus
24 );
25
26static PFN_SETRESTOREPTW vpfnSRSetRestorePointW = NULL;
27static HMODULE vhSrClientDll = NULL;
28
29
30static HRESULT InitializeComSecurity();
31
32
33DAPI_(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
58LExit:
59 if (FAILED(hr) && vhSrClientDll)
60 {
61 SrpUninitialize();
62 }
63
64 return hr;
65}
66
67DAPI_(void) SrpUninitialize()
68{
69 if (vhSrClientDll)
70 {
71 ::FreeLibrary(vhSrClientDll);
72 vhSrClientDll = NULL;
73 vpfnSRSetRestorePointW = NULL;
74 }
75}
76
77DAPI_(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
100LExit:
101 return hr;
102}
103
104
105// internal functions.
106
107static 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
245LExit:
246 if (pAcl)
247 {
248 ::LocalFree(pAcl);
249 }
250
251 return hr;
252}