diff options
author | Rob Mensching <rob@firegiant.com> | 2017-09-03 11:22:38 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2017-09-03 13:33:33 -0700 |
commit | 5d8375007754101ff2889d0e79486c8f9b7cf5ab (patch) | |
tree | a76d6fb6a38dd9f04a93ffcfd9d64e76779b3414 /src/dutil/aclutil.cpp | |
parent | 8e8da6dbc051ec884b5d439bb4f44dc027d05bbf (diff) | |
download | wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.tar.gz wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.tar.bz2 wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.zip |
Initial commit
Diffstat (limited to 'src/dutil/aclutil.cpp')
-rw-r--r-- | src/dutil/aclutil.cpp | 1030 |
1 files changed, 1030 insertions, 0 deletions
diff --git a/src/dutil/aclutil.cpp b/src/dutil/aclutil.cpp new file mode 100644 index 00000000..fc01ecc8 --- /dev/null +++ b/src/dutil/aclutil.cpp | |||
@@ -0,0 +1,1030 @@ | |||
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 | AclCheckAccess - determines if token has appropriate privileges | ||
7 | |||
8 | NOTE: paa->fDenyAccess and paa->dwAccessMask are ignored and must be zero | ||
9 | if hToken is NULL, the thread will be checked | ||
10 | if hToken is not NULL the token must be an impersonation token | ||
11 | ********************************************************************/ | ||
12 | extern "C" HRESULT DAPI AclCheckAccess( | ||
13 | __in HANDLE hToken, | ||
14 | __in ACL_ACCESS* paa | ||
15 | ) | ||
16 | { | ||
17 | HRESULT hr = S_OK; | ||
18 | PSID psid = NULL; | ||
19 | BOOL fIsMember = FALSE; | ||
20 | |||
21 | ExitOnNull(paa, hr, E_INVALIDARG, "Failed to check ACL access, because no acl access provided to check"); | ||
22 | Assert(0 == paa->fDenyAccess && 0 == paa->dwAccessMask); | ||
23 | |||
24 | if (paa->pwzAccountName) | ||
25 | { | ||
26 | hr = AclGetAccountSid(NULL, paa->pwzAccountName, &psid); | ||
27 | ExitOnFailure(hr, "failed to get SID for account: %ls", paa->pwzAccountName); | ||
28 | } | ||
29 | else | ||
30 | { | ||
31 | if (!::AllocateAndInitializeSid(&paa->sia, paa->nSubAuthorityCount, paa->nSubAuthority[0], paa->nSubAuthority[1], paa->nSubAuthority[2], paa->nSubAuthority[3], paa->nSubAuthority[4], paa->nSubAuthority[5], paa->nSubAuthority[6], paa->nSubAuthority[7], &psid)) | ||
32 | { | ||
33 | ExitWithLastError(hr, "failed to initialize SID"); | ||
34 | } | ||
35 | } | ||
36 | |||
37 | if (!::CheckTokenMembership(hToken, psid, &fIsMember)) | ||
38 | { | ||
39 | ExitWithLastError(hr, "failed to check membership"); | ||
40 | } | ||
41 | |||
42 | fIsMember ? hr = S_OK : hr = S_FALSE; | ||
43 | |||
44 | LExit: | ||
45 | if (psid) | ||
46 | { | ||
47 | ::FreeSid(psid); // TODO: does this have bad behavior if SID was allocated by Heap from AclGetAccountSid? | ||
48 | } | ||
49 | |||
50 | return hr; | ||
51 | } | ||
52 | |||
53 | |||
54 | /******************************************************************** | ||
55 | AclCheckAdministratorAccess - determines if token has Administrator privileges | ||
56 | |||
57 | NOTE: if hToken is NULL, the thread will be checked | ||
58 | if hToken is not NULL the token must be an impersonation token | ||
59 | ********************************************************************/ | ||
60 | extern "C" HRESULT DAPI AclCheckAdministratorAccess( | ||
61 | __in HANDLE hToken | ||
62 | ) | ||
63 | { | ||
64 | ACL_ACCESS aa; | ||
65 | SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY; | ||
66 | |||
67 | memset(&aa, 0, sizeof(aa)); | ||
68 | aa.sia = siaNt; | ||
69 | aa.nSubAuthorityCount = 2; | ||
70 | aa.nSubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID; | ||
71 | aa.nSubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS; | ||
72 | |||
73 | return AclCheckAccess(hToken, &aa); | ||
74 | } | ||
75 | |||
76 | |||
77 | /******************************************************************** | ||
78 | AclCheckLocalSystemAccess - determines if token has LocalSystem privileges | ||
79 | |||
80 | NOTE: if hToken is NULL, the thread will be checked | ||
81 | if hToken is not NULL the token must be an impersonation token | ||
82 | ********************************************************************/ | ||
83 | extern "C" HRESULT DAPI AclCheckLocalSystemAccess( | ||
84 | __in HANDLE hToken | ||
85 | ) | ||
86 | { | ||
87 | ACL_ACCESS aa; | ||
88 | SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY; | ||
89 | |||
90 | memset(&aa, 0, sizeof(aa)); | ||
91 | aa.sia = siaNt; | ||
92 | aa.nSubAuthorityCount = 1; | ||
93 | aa.nSubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID; | ||
94 | |||
95 | return AclCheckAccess(hToken, &aa); | ||
96 | } | ||
97 | |||
98 | |||
99 | /******************************************************************** | ||
100 | AclGetWellKnownSid - returns a SID for the specified account | ||
101 | |||
102 | ********************************************************************/ | ||
103 | extern "C" HRESULT DAPI AclGetWellKnownSid( | ||
104 | __in WELL_KNOWN_SID_TYPE wkst, | ||
105 | __deref_out PSID* ppsid | ||
106 | ) | ||
107 | { | ||
108 | Assert(ppsid); | ||
109 | |||
110 | HRESULT hr = S_OK;; | ||
111 | PSID psid = NULL; | ||
112 | DWORD cbSid = SECURITY_MAX_SID_SIZE; | ||
113 | |||
114 | PSID psidTemp = NULL; | ||
115 | #if(_WIN32_WINNT < 0x0501) | ||
116 | SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY; | ||
117 | SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY; | ||
118 | SID_IDENTIFIER_AUTHORITY siaCreator = SECURITY_CREATOR_SID_AUTHORITY; | ||
119 | BOOL fSuccess = FALSE; | ||
120 | #endif | ||
121 | |||
122 | // | ||
123 | // allocate memory for the SID and get it | ||
124 | // | ||
125 | psid = static_cast<PSID>(MemAlloc(cbSid, TRUE)); | ||
126 | ExitOnNull(psid, hr, E_OUTOFMEMORY, "failed allocate memory for well known SID"); | ||
127 | |||
128 | #if(_WIN32_WINNT < 0x0501) | ||
129 | switch (wkst) | ||
130 | { | ||
131 | case WinWorldSid: // Everyone | ||
132 | fSuccess = ::AllocateAndInitializeSid(&siaWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
133 | break; | ||
134 | case WinAuthenticatedUserSid: // Authenticated Users | ||
135 | fSuccess = ::AllocateAndInitializeSid(&siaNT, 1, SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
136 | break; | ||
137 | case WinLocalSystemSid: // LocalSystem | ||
138 | fSuccess = ::AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
139 | break; | ||
140 | case WinLocalServiceSid: // LocalService | ||
141 | fSuccess = ::AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
142 | break; | ||
143 | case WinNetworkServiceSid: // NetworkService | ||
144 | fSuccess = ::AllocateAndInitializeSid(&siaNT, 1, SECURITY_NETWORK_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
145 | break; | ||
146 | case WinBuiltinGuestsSid: // Guests | ||
147 | fSuccess = ::AllocateAndInitializeSid(&siaNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
148 | break; | ||
149 | case WinBuiltinAdministratorsSid: // Administrators | ||
150 | fSuccess = ::AllocateAndInitializeSid(&siaNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
151 | break; | ||
152 | case WinBuiltinUsersSid: // Users | ||
153 | fSuccess = ::AllocateAndInitializeSid(&siaNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
154 | break; | ||
155 | case WinCreatorOwnerSid: //CREATOR OWNER | ||
156 | fSuccess = ::AllocateAndInitializeSid(&siaCreator, 1, SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
157 | break; | ||
158 | case WinInteractiveSid: // INTERACTIVE | ||
159 | fSuccess = ::AllocateAndInitializeSid(&siaNT, 1, SECURITY_INTERACTIVE_RID, 0, 0, 0, 0, 0, 0, 0, &psidTemp); | ||
160 | break; | ||
161 | default: | ||
162 | hr = E_INVALIDARG; | ||
163 | ExitOnFailure(hr, "unknown well known SID: %d", wkst); | ||
164 | } | ||
165 | |||
166 | if (!fSuccess) | ||
167 | ExitOnLastError(hr, "failed to allocate well known SID: %d", wkst); | ||
168 | |||
169 | if (!::CopySid(cbSid, psid, psidTemp)) | ||
170 | ExitOnLastError(hr, "failed to create well known SID: %d", wkst); | ||
171 | #else | ||
172 | Assert(NULL == psidTemp); | ||
173 | if (!::CreateWellKnownSid(wkst, NULL, psid, &cbSid)) | ||
174 | { | ||
175 | ExitWithLastError(hr, "failed to create well known SID: %d", wkst); | ||
176 | } | ||
177 | #endif | ||
178 | |||
179 | *ppsid = psid; | ||
180 | psid = NULL; // null it here so it won't be released below | ||
181 | |||
182 | Assert(S_OK == hr && ::IsValidSid(*ppsid)); | ||
183 | LExit: | ||
184 | if (psidTemp) | ||
185 | { | ||
186 | ::FreeSid(psidTemp); | ||
187 | } | ||
188 | |||
189 | ReleaseMem(psid); | ||
190 | |||
191 | return hr; | ||
192 | } | ||
193 | |||
194 | |||
195 | /******************************************************************** | ||
196 | AclGetAccountSid - returns a SID for the specified account | ||
197 | |||
198 | ********************************************************************/ | ||
199 | extern "C" HRESULT DAPI AclGetAccountSid( | ||
200 | __in_opt LPCWSTR wzSystem, | ||
201 | __in_z LPCWSTR wzAccount, | ||
202 | __deref_out PSID* ppsid | ||
203 | ) | ||
204 | { | ||
205 | Assert(wzAccount && *wzAccount && ppsid); | ||
206 | |||
207 | HRESULT hr = S_OK; | ||
208 | UINT er = ERROR_SUCCESS; | ||
209 | PSID psid = NULL; | ||
210 | DWORD cbSid = SECURITY_MAX_SID_SIZE; | ||
211 | LPWSTR pwzDomainName = NULL; | ||
212 | DWORD cbDomainName = 255; | ||
213 | SID_NAME_USE peUse; | ||
214 | |||
215 | // | ||
216 | // allocate memory for the SID and domain name | ||
217 | // | ||
218 | psid = static_cast<PSID>(MemAlloc(cbSid, TRUE)); | ||
219 | ExitOnNull(psid, hr, E_OUTOFMEMORY, "failed to allocate memory for SID"); | ||
220 | hr = StrAlloc(&pwzDomainName, cbDomainName); | ||
221 | ExitOnFailure(hr, "failed to allocate string for domain name"); | ||
222 | |||
223 | // | ||
224 | // try to lookup the account now | ||
225 | // | ||
226 | if (!::LookupAccountNameW(wzSystem, wzAccount, psid, &cbSid, pwzDomainName, &cbDomainName, &peUse)) | ||
227 | { | ||
228 | // if one of the buffers wasn't large enough | ||
229 | er = ::GetLastError(); | ||
230 | if (ERROR_INSUFFICIENT_BUFFER == er) | ||
231 | { | ||
232 | if (SECURITY_MAX_SID_SIZE < cbSid) | ||
233 | { | ||
234 | PSID psidNew = static_cast<PSID>(MemReAlloc(psid, cbSid, TRUE)); | ||
235 | ExitOnNullWithLastError(psidNew, hr, "failed to allocate memory for account: %ls", wzAccount); | ||
236 | |||
237 | psid = psidNew; | ||
238 | } | ||
239 | if (255 < cbDomainName) | ||
240 | { | ||
241 | hr = StrAlloc(&pwzDomainName, cbDomainName); | ||
242 | ExitOnFailure(hr, "failed to allocate string for domain name"); | ||
243 | } | ||
244 | |||
245 | if (!::LookupAccountNameW(wzSystem, wzAccount, psid, &cbSid, pwzDomainName, &cbDomainName, &peUse)) | ||
246 | { | ||
247 | ExitWithLastError(hr, "failed to lookup account: %ls", wzAccount); | ||
248 | } | ||
249 | } | ||
250 | else | ||
251 | { | ||
252 | ExitOnWin32Error(er, hr, "failed to lookup account: %ls", wzAccount); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | *ppsid = psid; | ||
257 | psid = NULL; | ||
258 | |||
259 | hr = S_OK; | ||
260 | LExit: | ||
261 | ReleaseStr(pwzDomainName); | ||
262 | ReleaseMem(psid); | ||
263 | |||
264 | return hr; | ||
265 | } | ||
266 | |||
267 | |||
268 | /******************************************************************** | ||
269 | AclGetAccountSidString - gets a string version of the user's SID | ||
270 | |||
271 | NOTE: ppwzSid should be freed with StrFree() | ||
272 | ********************************************************************/ | ||
273 | extern "C" HRESULT DAPI AclGetAccountSidString( | ||
274 | __in_z LPCWSTR wzSystem, | ||
275 | __in_z LPCWSTR wzAccount, | ||
276 | __deref_out_z LPWSTR* ppwzSid | ||
277 | ) | ||
278 | { | ||
279 | Assert(ppwzSid); | ||
280 | HRESULT hr = S_OK; | ||
281 | PSID psid = NULL; | ||
282 | LPWSTR pwz = NULL; | ||
283 | |||
284 | *ppwzSid = NULL; | ||
285 | |||
286 | hr = AclGetAccountSid(wzSystem, wzAccount, &psid); | ||
287 | ExitOnFailure(hr, "failed to get SID for account: %ls", wzAccount); | ||
288 | Assert(::IsValidSid(psid)); | ||
289 | |||
290 | if (!::ConvertSidToStringSidW(psid, &pwz)) | ||
291 | { | ||
292 | ExitWithLastError(hr, "failed to convert SID to string for Account: %ls", wzAccount); | ||
293 | } | ||
294 | |||
295 | hr = StrAllocString(ppwzSid, pwz, 0); | ||
296 | |||
297 | LExit: | ||
298 | if (FAILED(hr)) | ||
299 | { | ||
300 | ReleaseNullStr(*ppwzSid); | ||
301 | } | ||
302 | |||
303 | if (pwz) | ||
304 | { | ||
305 | ::LocalFree(pwz); | ||
306 | } | ||
307 | |||
308 | if (psid) | ||
309 | { | ||
310 | AclFreeSid(psid); | ||
311 | } | ||
312 | |||
313 | return hr; | ||
314 | } | ||
315 | |||
316 | |||
317 | /******************************************************************** | ||
318 | AclCreateDacl - creates a DACL from ACL_ACE structures | ||
319 | |||
320 | ********************************************************************/ | ||
321 | extern "C" HRESULT DAPI AclCreateDacl( | ||
322 | __in_ecount(cDeny) ACL_ACE rgaaDeny[], | ||
323 | __in DWORD cDeny, | ||
324 | __in_ecount(cAllow) ACL_ACE rgaaAllow[], | ||
325 | __in DWORD cAllow, | ||
326 | __deref_out ACL** ppAcl | ||
327 | ) | ||
328 | { | ||
329 | Assert(ppAcl); | ||
330 | HRESULT hr = S_OK; | ||
331 | ACL* pAcl = NULL; | ||
332 | DWORD cbAcl = 0; | ||
333 | DWORD i; | ||
334 | |||
335 | *ppAcl = NULL; | ||
336 | |||
337 | // initialize the ACL | ||
338 | cbAcl = sizeof(ACL); | ||
339 | for (i = 0; i < cDeny; ++i) | ||
340 | { | ||
341 | cbAcl += sizeof(ACCESS_DENIED_ACE) + ::GetLengthSid(rgaaDeny[i].psid) - sizeof(DWORD); | ||
342 | } | ||
343 | |||
344 | for (i = 0; i < cAllow; ++i) | ||
345 | { | ||
346 | cbAcl += sizeof(ACCESS_ALLOWED_ACE) + ::GetLengthSid(rgaaAllow[i].psid) - sizeof(DWORD); | ||
347 | } | ||
348 | |||
349 | pAcl = static_cast<ACL*>(MemAlloc(cbAcl, TRUE)); | ||
350 | ExitOnNull(pAcl, hr, E_OUTOFMEMORY, "failed to allocate ACL"); | ||
351 | |||
352 | #pragma prefast(push) | ||
353 | #pragma prefast(disable:25029) | ||
354 | if (!::InitializeAcl(pAcl, cbAcl, ACL_REVISION)) | ||
355 | #pragma prefast(pop) | ||
356 | { | ||
357 | ExitWithLastError(hr, "failed to initialize ACL"); | ||
358 | } | ||
359 | |||
360 | // add in the ACEs (denied first) | ||
361 | for (i = 0; i < cDeny; ++i) | ||
362 | { | ||
363 | #pragma prefast(push) | ||
364 | #pragma prefast(disable:25029) | ||
365 | if (!::AddAccessDeniedAceEx(pAcl, ACL_REVISION, rgaaDeny[i].dwFlags, rgaaDeny[i].dwMask, rgaaDeny[i].psid)) | ||
366 | #pragma prefast(pop) | ||
367 | { | ||
368 | ExitWithLastError(hr, "failed to add access denied ACE #%d to ACL", i); | ||
369 | } | ||
370 | } | ||
371 | for (i = 0; i < cAllow; ++i) | ||
372 | { | ||
373 | #pragma prefast(push) | ||
374 | #pragma prefast(disable:25029) | ||
375 | if (!::AddAccessAllowedAceEx(pAcl, ACL_REVISION, rgaaAllow[i].dwFlags, rgaaAllow[i].dwMask, rgaaAllow[i].psid)) | ||
376 | #pragma prefast(pop) | ||
377 | { | ||
378 | ExitWithLastError(hr, "failed to add access allowed ACE #$d to ACL", i); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | *ppAcl = pAcl; | ||
383 | pAcl = NULL; | ||
384 | AssertSz(::IsValidAcl(*ppAcl), "AclCreateDacl() - created invalid ACL"); | ||
385 | Assert(S_OK == hr); | ||
386 | LExit: | ||
387 | if (pAcl) | ||
388 | { | ||
389 | AclFreeDacl(pAcl); | ||
390 | } | ||
391 | |||
392 | return hr; | ||
393 | } | ||
394 | |||
395 | |||
396 | /******************************************************************** | ||
397 | AclAddToDacl - creates a new DACL from an ACL plus new ACL_ACE structure | ||
398 | |||
399 | ********************************************************************/ | ||
400 | extern "C" HRESULT DAPI AclAddToDacl( | ||
401 | __in ACL* pAcl, | ||
402 | __in_ecount_opt(cDeny) const ACL_ACE rgaaDeny[], | ||
403 | __in DWORD cDeny, | ||
404 | __in_ecount_opt(cAllow) const ACL_ACE rgaaAllow[], | ||
405 | __in DWORD cAllow, | ||
406 | __deref_out ACL** ppAclNew | ||
407 | ) | ||
408 | { | ||
409 | Assert(pAcl && ::IsValidAcl(pAcl) && ppAclNew); | ||
410 | HRESULT hr = S_OK; | ||
411 | |||
412 | ACL_SIZE_INFORMATION asi; | ||
413 | ACL_ACE* paaNewDeny = NULL; | ||
414 | DWORD cNewDeny = 0; | ||
415 | ACL_ACE* paaNewAllow = NULL; | ||
416 | DWORD cNewAllow = 0; | ||
417 | |||
418 | ACCESS_ALLOWED_ACE* paaa; | ||
419 | ACCESS_DENIED_ACE* pada; | ||
420 | DWORD i; | ||
421 | |||
422 | // allocate memory for all the new ACEs (NOTE: this over calculates the memory necessary, but that's okay) | ||
423 | if (!::GetAclInformation(pAcl, &asi, sizeof(asi), AclSizeInformation)) | ||
424 | { | ||
425 | ExitWithLastError(hr, "failed to get information about original ACL"); | ||
426 | } | ||
427 | |||
428 | if ((asi.AceCount + cDeny) < asi.AceCount || // check for overflow | ||
429 | (asi.AceCount + cDeny) < cDeny || // check for overflow | ||
430 | (asi.AceCount + cDeny) >= MAXSIZE_T / sizeof(ACL_ACE)) | ||
431 | { | ||
432 | hr = E_OUTOFMEMORY; | ||
433 | ExitOnFailure(hr, "Not enough memory to allocate %d ACEs", (asi.AceCount + cDeny)); | ||
434 | } | ||
435 | |||
436 | paaNewDeny = static_cast<ACL_ACE*>(MemAlloc(sizeof(ACL_ACE) * (asi.AceCount + cDeny), TRUE)); | ||
437 | ExitOnNull(paaNewDeny, hr, E_OUTOFMEMORY, "failed to allocate memory for new deny ACEs"); | ||
438 | |||
439 | if ((asi.AceCount + cAllow) < asi.AceCount || // check for overflow | ||
440 | (asi.AceCount + cAllow) < cAllow || // check for overflow | ||
441 | (asi.AceCount + cAllow) >= MAXSIZE_T / sizeof(ACL_ACE)) | ||
442 | { | ||
443 | hr = E_OUTOFMEMORY; | ||
444 | ExitOnFailure(hr, "Not enough memory to allocate %d ACEs", (asi.AceCount + cAllow)); | ||
445 | } | ||
446 | |||
447 | paaNewAllow = static_cast<ACL_ACE*>(MemAlloc(sizeof(ACL_ACE) * (asi.AceCount + cAllow), TRUE)); | ||
448 | ExitOnNull(paaNewAllow, hr, E_OUTOFMEMORY, "failed to allocate memory for new allow ACEs"); | ||
449 | |||
450 | // fill in the new structures with old data then new data (denied first) | ||
451 | for (i = 0; i < asi.AceCount; ++i) | ||
452 | { | ||
453 | if (!::GetAce(pAcl, i, reinterpret_cast<LPVOID*>(&pada))) | ||
454 | { | ||
455 | ExitWithLastError(hr, "failed to get ACE #%d from ACL", i); | ||
456 | } | ||
457 | |||
458 | if (ACCESS_DENIED_ACE_TYPE != pada->Header.AceType) | ||
459 | { | ||
460 | continue; // skip non-denied aces | ||
461 | } | ||
462 | |||
463 | paaNewDeny[i].dwFlags = pada->Header.AceFlags; | ||
464 | paaNewDeny[i].dwMask = pada->Mask; | ||
465 | paaNewDeny[i].psid = reinterpret_cast<PSID>(&(pada->SidStart)); | ||
466 | ++cNewDeny; | ||
467 | } | ||
468 | |||
469 | memcpy(paaNewDeny + cNewDeny, rgaaDeny, sizeof(ACL_ACE) * cDeny); | ||
470 | cNewDeny += cDeny; | ||
471 | |||
472 | |||
473 | for (i = 0; i < asi.AceCount; ++i) | ||
474 | { | ||
475 | if (!::GetAce(pAcl, i, reinterpret_cast<LPVOID*>(&paaa))) | ||
476 | { | ||
477 | ExitWithLastError(hr, "failed to get ACE #%d from ACL", i); | ||
478 | } | ||
479 | |||
480 | if (ACCESS_ALLOWED_ACE_TYPE != paaa->Header.AceType) | ||
481 | { | ||
482 | continue; // skip non-allowed aces | ||
483 | } | ||
484 | |||
485 | paaNewAllow[i].dwFlags = paaa->Header.AceFlags; | ||
486 | paaNewAllow[i].dwMask = paaa->Mask; | ||
487 | paaNewAllow[i].psid = reinterpret_cast<PSID>(&(paaa->SidStart)); | ||
488 | ++cNewAllow; | ||
489 | } | ||
490 | |||
491 | memcpy(paaNewAllow + cNewAllow, rgaaAllow, sizeof(ACL_ACE) * cAllow); | ||
492 | cNewAllow += cAllow; | ||
493 | |||
494 | // create the dacl with the new | ||
495 | hr = AclCreateDacl(paaNewDeny, cNewDeny, paaNewAllow, cNewAllow, ppAclNew); | ||
496 | ExitOnFailure(hr, "failed to create new ACL from existing ACL"); | ||
497 | |||
498 | AssertSz(::IsValidAcl(*ppAclNew), "AclAddToDacl() - created invalid ACL"); | ||
499 | Assert(S_OK == hr); | ||
500 | LExit: | ||
501 | ReleaseMem(paaNewAllow); | ||
502 | ReleaseMem(paaNewDeny); | ||
503 | |||
504 | return hr; | ||
505 | } | ||
506 | |||
507 | |||
508 | /******************************************************************** | ||
509 | AclMergeDacls - creates a new DACL from two existing ACLs | ||
510 | |||
511 | ********************************************************************/ | ||
512 | extern "C" HRESULT DAPI AclMergeDacls( | ||
513 | __in const ACL* pAcl1, | ||
514 | __in const ACL* pAcl2, | ||
515 | __deref_out ACL** ppAclNew | ||
516 | ) | ||
517 | { | ||
518 | HRESULT hr = E_NOTIMPL; | ||
519 | |||
520 | Assert(pAcl1 && pAcl2 && ppAclNew); | ||
521 | UNREFERENCED_PARAMETER(pAcl1); | ||
522 | UNREFERENCED_PARAMETER(pAcl2); | ||
523 | UNREFERENCED_PARAMETER(ppAclNew); | ||
524 | |||
525 | //LExit: | ||
526 | return hr; | ||
527 | } | ||
528 | |||
529 | |||
530 | /******************************************************************** | ||
531 | AclCreateDaclOld - creates a DACL from an ACL_ACCESS structure | ||
532 | |||
533 | ********************************************************************/ | ||
534 | extern "C" HRESULT DAPI AclCreateDaclOld( | ||
535 | __in_ecount(cAclAccesses) ACL_ACCESS* paa, | ||
536 | __in DWORD cAclAccesses, | ||
537 | __deref_out ACL** ppACL | ||
538 | ) | ||
539 | { | ||
540 | Assert(ppACL); | ||
541 | HRESULT hr = S_OK; | ||
542 | DWORD* pdwAccessMask = NULL; | ||
543 | PSID* ppsid = NULL; | ||
544 | |||
545 | DWORD i; | ||
546 | int cbAcl; | ||
547 | |||
548 | *ppACL = NULL; | ||
549 | |||
550 | // | ||
551 | // create the SIDs and calculate the space for the ACL | ||
552 | // | ||
553 | pdwAccessMask = static_cast<DWORD*>(MemAlloc(sizeof(DWORD) * cAclAccesses, TRUE)); | ||
554 | ExitOnNull(pdwAccessMask, hr, E_OUTOFMEMORY, "failed allocate memory for access mask"); | ||
555 | ppsid = static_cast<PSID*>(MemAlloc(sizeof(PSID) * cAclAccesses, TRUE)); | ||
556 | ExitOnNull(ppsid, hr, E_OUTOFMEMORY, "failed allocate memory for sid"); | ||
557 | |||
558 | cbAcl = sizeof (ACL); // start with the size of the header | ||
559 | for (i = 0; i < cAclAccesses; ++i) | ||
560 | { | ||
561 | if (paa[i].pwzAccountName) | ||
562 | { | ||
563 | hr = AclGetAccountSid(NULL, paa[i].pwzAccountName, ppsid + i); | ||
564 | ExitOnFailure(hr, "failed to get SID for account: %ls", paa[i].pwzAccountName); | ||
565 | } | ||
566 | else | ||
567 | { | ||
568 | if ((!::AllocateAndInitializeSid(&paa[i].sia, paa[i].nSubAuthorityCount, | ||
569 | paa[i].nSubAuthority[0], paa[i].nSubAuthority[1], | ||
570 | paa[i].nSubAuthority[2], paa[i].nSubAuthority[3], | ||
571 | paa[i].nSubAuthority[4], paa[i].nSubAuthority[5], | ||
572 | paa[i].nSubAuthority[6], paa[i].nSubAuthority[7], | ||
573 | (void**)(ppsid + i)))) | ||
574 | { | ||
575 | ExitWithLastError(hr, "failed to initialize SIDs #%u", i); | ||
576 | } | ||
577 | } | ||
578 | |||
579 | // add the newly allocated SID size to the count of bytes for this ACL | ||
580 | cbAcl +=::GetLengthSid(*(ppsid + i)) - sizeof(DWORD); | ||
581 | if (paa[i].fDenyAccess) | ||
582 | { | ||
583 | cbAcl += sizeof(ACCESS_DENIED_ACE); | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | cbAcl += sizeof(ACCESS_ALLOWED_ACE); | ||
588 | } | ||
589 | |||
590 | pdwAccessMask[i] = paa[i].dwAccessMask; | ||
591 | } | ||
592 | |||
593 | // | ||
594 | // allocate the ACL and set the appropriate ACEs | ||
595 | // | ||
596 | *ppACL = static_cast<ACL*>(MemAlloc(cbAcl, FALSE)); | ||
597 | ExitOnNull(*ppACL, hr, E_OUTOFMEMORY, "failed allocate memory for ACL"); | ||
598 | |||
599 | #pragma prefast(push) | ||
600 | #pragma prefast(disable:25029) | ||
601 | if (!::InitializeAcl(*ppACL, cbAcl, ACL_REVISION)) | ||
602 | #pragma prefast(pop) | ||
603 | { | ||
604 | ExitWithLastError(hr, "failed to initialize ACLs"); | ||
605 | } | ||
606 | |||
607 | // add an access-allowed ACE for each of the SIDs | ||
608 | for (i = 0; i < cAclAccesses; ++i) | ||
609 | { | ||
610 | if (paa[i].fDenyAccess) | ||
611 | { | ||
612 | #pragma prefast(push) | ||
613 | #pragma prefast(disable:25029) | ||
614 | if (!::AddAccessDeniedAceEx(*ppACL, ACL_REVISION, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, pdwAccessMask[i], *(ppsid + i))) | ||
615 | #pragma prefast(pop) | ||
616 | { | ||
617 | ExitWithLastError(hr, "failed to add access denied for ACE"); | ||
618 | } | ||
619 | } | ||
620 | else | ||
621 | { | ||
622 | #pragma prefast(push) | ||
623 | #pragma prefast(disable:25029) | ||
624 | if (!::AddAccessAllowedAceEx(*ppACL, ACL_REVISION, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, pdwAccessMask[i], *(ppsid + i))) | ||
625 | #pragma prefast(pop) | ||
626 | { | ||
627 | ExitWithLastError(hr, "failed to add access allowed for ACE"); | ||
628 | } | ||
629 | } | ||
630 | } | ||
631 | |||
632 | LExit: | ||
633 | if (FAILED(hr)) | ||
634 | { | ||
635 | ReleaseNullMem(*ppACL); | ||
636 | } | ||
637 | |||
638 | if (ppsid) | ||
639 | { | ||
640 | for (i = 0; i < cAclAccesses; ++i) | ||
641 | { | ||
642 | if (ppsid[i]) | ||
643 | { | ||
644 | ::FreeSid(ppsid[i]); | ||
645 | } | ||
646 | } | ||
647 | |||
648 | MemFree(ppsid); | ||
649 | } | ||
650 | |||
651 | ReleaseMem(pdwAccessMask); | ||
652 | |||
653 | return hr; | ||
654 | } | ||
655 | |||
656 | |||
657 | /******************************************************************** | ||
658 | AclCreateSecurityDescriptorFromDacl - creates a self-relative security | ||
659 | descriptor from an existing DACL | ||
660 | |||
661 | ********************************************************************/ | ||
662 | extern "C" HRESULT DAPI AclCreateSecurityDescriptorFromDacl( | ||
663 | __in ACL* pACL, | ||
664 | __deref_out SECURITY_DESCRIPTOR** ppsd | ||
665 | ) | ||
666 | { | ||
667 | HRESULT hr = S_OK; | ||
668 | |||
669 | SECURITY_DESCRIPTOR sd; | ||
670 | DWORD cbSD; | ||
671 | |||
672 | ExitOnNull(pACL, hr, E_INVALIDARG, "Failed to create security descriptor from DACL, because no DACL was provided"); | ||
673 | ExitOnNull(ppsd, hr, E_INVALIDARG, "Failed to create security descriptor from DACL, because no output object was provided"); | ||
674 | |||
675 | *ppsd = NULL; | ||
676 | |||
677 | // | ||
678 | // create the absolute security descriptor | ||
679 | // | ||
680 | |||
681 | // initialize our security descriptor, throw the ACL into it, and set the owner | ||
682 | #pragma prefast(push) | ||
683 | #pragma prefast(disable:25028) // We only call this when pACL isn't NULL, so this call is safe according to the docs | ||
684 | #pragma prefast(disable:25029) | ||
685 | if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) || | ||
686 | (!::SetSecurityDescriptorDacl(&sd, TRUE, pACL, FALSE)) || | ||
687 | (!::SetSecurityDescriptorOwner(&sd, NULL, FALSE))) | ||
688 | #pragma prefast(pop) | ||
689 | { | ||
690 | ExitWithLastError(hr, "failed to initialize security descriptor"); | ||
691 | } | ||
692 | |||
693 | // | ||
694 | // create the self-relative security descriptor | ||
695 | // | ||
696 | cbSD = ::GetSecurityDescriptorLength(&sd); | ||
697 | *ppsd = static_cast<SECURITY_DESCRIPTOR*>(MemAlloc(cbSD, FALSE)); | ||
698 | ExitOnNull(*ppsd, hr, E_OUTOFMEMORY, "failed allocate memory for security descriptor"); | ||
699 | |||
700 | ::MakeSelfRelativeSD(&sd, (BYTE*)*ppsd, &cbSD); | ||
701 | Assert(::IsValidSecurityDescriptor(*ppsd)); | ||
702 | |||
703 | LExit: | ||
704 | if (FAILED(hr) && NULL != ppsd && NULL != *ppsd) | ||
705 | { | ||
706 | MemFree(*ppsd); | ||
707 | *ppsd = NULL; | ||
708 | } | ||
709 | |||
710 | return hr; | ||
711 | } | ||
712 | |||
713 | |||
714 | /******************************************************************** | ||
715 | AclCreateSecurityDescriptor - creates a self-relative security descriptor from an | ||
716 | ACL_ACCESS structure | ||
717 | |||
718 | NOTE: ppsd should be freed with AclFreeSecurityDescriptor() | ||
719 | ********************************************************************/ | ||
720 | extern "C" HRESULT DAPI AclCreateSecurityDescriptor( | ||
721 | __in_ecount(cAclAccesses) ACL_ACCESS* paa, | ||
722 | __in DWORD cAclAccesses, | ||
723 | __deref_out SECURITY_DESCRIPTOR** ppsd | ||
724 | ) | ||
725 | { | ||
726 | Assert(ppsd); | ||
727 | HRESULT hr = S_OK; | ||
728 | |||
729 | ACL* pACL; | ||
730 | |||
731 | *ppsd = NULL; | ||
732 | |||
733 | // | ||
734 | // create the DACL | ||
735 | // | ||
736 | hr = AclCreateDaclOld(paa, cAclAccesses, &pACL); | ||
737 | ExitOnFailure(hr, "failed to create DACL for security descriptor"); | ||
738 | |||
739 | // | ||
740 | // create self-relative security descriptor | ||
741 | // | ||
742 | hr = AclCreateSecurityDescriptorFromDacl(pACL, ppsd); | ||
743 | |||
744 | LExit: | ||
745 | return hr; | ||
746 | } | ||
747 | |||
748 | |||
749 | /******************************************************************** | ||
750 | AclCreateSecurityDescriptorFromString - creates a self-relative security | ||
751 | descriptor from an SDDL string | ||
752 | |||
753 | NOTE: ppsd should be freed with AclFreeSecurityDescriptor() | ||
754 | ********************************************************************/ | ||
755 | extern "C" HRESULT DAPI AclCreateSecurityDescriptorFromString( | ||
756 | __deref_out SECURITY_DESCRIPTOR** ppsd, | ||
757 | __in_z __format_string LPCWSTR wzSddlFormat, | ||
758 | ... | ||
759 | ) | ||
760 | { | ||
761 | Assert(ppsd); | ||
762 | HRESULT hr = S_OK; | ||
763 | LPWSTR pwzSddl = NULL; | ||
764 | va_list args; | ||
765 | PSECURITY_DESCRIPTOR psd = NULL; | ||
766 | DWORD cbSD = 0; | ||
767 | |||
768 | *ppsd = NULL; | ||
769 | |||
770 | va_start(args, wzSddlFormat); | ||
771 | hr = StrAllocFormattedArgs(&pwzSddl, wzSddlFormat, args); | ||
772 | va_end(args); | ||
773 | ExitOnFailure(hr, "failed to create SDDL string for format: %ls", wzSddlFormat); | ||
774 | |||
775 | if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(pwzSddl, SDDL_REVISION_1, &psd, &cbSD)) | ||
776 | { | ||
777 | ExitWithLastError(hr, "failed to create security descriptor from SDDL: %ls", pwzSddl); | ||
778 | } | ||
779 | |||
780 | *ppsd = static_cast<SECURITY_DESCRIPTOR*>(MemAlloc(cbSD, FALSE)); | ||
781 | ExitOnNull(*ppsd, hr, E_OUTOFMEMORY, "failed to allocate memory for security descriptor"); | ||
782 | |||
783 | memcpy(*ppsd, psd, cbSD); | ||
784 | Assert(::IsValidSecurityDescriptor(*ppsd)); | ||
785 | |||
786 | Assert(S_OK == hr); | ||
787 | |||
788 | LExit: | ||
789 | if (FAILED(hr) && NULL != ppsd && NULL != *ppsd) | ||
790 | { | ||
791 | MemFree(*ppsd); | ||
792 | *ppsd = NULL; | ||
793 | } | ||
794 | |||
795 | if (psd) | ||
796 | { | ||
797 | ::LocalFree(psd); | ||
798 | } | ||
799 | |||
800 | ReleaseStr(pwzSddl); | ||
801 | return hr; | ||
802 | } | ||
803 | |||
804 | |||
805 | /******************************************************************** | ||
806 | AclDuplicateSecurityDescriptor - creates a copy of a self-relative security descriptor | ||
807 | |||
808 | NOTE: passed in security descriptor must be in self-relative format | ||
809 | ********************************************************************/ | ||
810 | extern "C" HRESULT DAPI AclDuplicateSecurityDescriptor( | ||
811 | __in SECURITY_DESCRIPTOR* psd, | ||
812 | __deref_out SECURITY_DESCRIPTOR** ppsd | ||
813 | ) | ||
814 | { | ||
815 | HRESULT hr = S_OK; | ||
816 | DWORD cbSD; | ||
817 | |||
818 | ExitOnNull(ppsd, hr, E_INVALIDARG, "Failed to get duplicate ACL security descriptor because no place to output was provided"); | ||
819 | *ppsd = NULL; | ||
820 | |||
821 | // | ||
822 | // create the self-relative security descriptor | ||
823 | // | ||
824 | cbSD = ::GetSecurityDescriptorLength(psd); | ||
825 | *ppsd = static_cast<SECURITY_DESCRIPTOR*>(MemAlloc(cbSD, 0)); | ||
826 | ExitOnNull(*ppsd, hr, E_OUTOFMEMORY, "failed allocate memory for security descriptor"); | ||
827 | |||
828 | memcpy(*ppsd, psd, cbSD); | ||
829 | Assert(::IsValidSecurityDescriptor(*ppsd)); | ||
830 | |||
831 | LExit: | ||
832 | if (FAILED(hr) && NULL != ppsd && NULL != *ppsd) | ||
833 | { | ||
834 | MemFree(*ppsd); | ||
835 | *ppsd = NULL; | ||
836 | } | ||
837 | |||
838 | return hr; | ||
839 | } | ||
840 | |||
841 | |||
842 | /******************************************************************** | ||
843 | AclGetSecurityDescriptor - returns self-relative security descriptor for named object | ||
844 | |||
845 | NOTE: free ppsd with AclFreeSecurityDescriptor() | ||
846 | ********************************************************************/ | ||
847 | extern "C" HRESULT DAPI AclGetSecurityDescriptor( | ||
848 | __in_z LPCWSTR wzObject, | ||
849 | __in SE_OBJECT_TYPE sot, | ||
850 | __in SECURITY_INFORMATION securityInformation, | ||
851 | __deref_out SECURITY_DESCRIPTOR** ppsd | ||
852 | ) | ||
853 | { | ||
854 | HRESULT hr = S_OK; | ||
855 | DWORD er; | ||
856 | PSECURITY_DESCRIPTOR psd = NULL; | ||
857 | DWORD cbSD; | ||
858 | |||
859 | ExitOnNull(ppsd, hr, E_INVALIDARG, "Failed to get ACL Security Descriptor because no place to output was provided"); | ||
860 | *ppsd = NULL; | ||
861 | |||
862 | // get the security descriptor for the object | ||
863 | er = ::GetNamedSecurityInfoW(const_cast<LPWSTR>(wzObject), sot, securityInformation, NULL, NULL, NULL, NULL, &psd); | ||
864 | ExitOnWin32Error(er, hr, "failed to get security info from object: %ls", wzObject); | ||
865 | Assert(::IsValidSecurityDescriptor(psd)); | ||
866 | |||
867 | // copy the self-relative security descriptor | ||
868 | cbSD = ::GetSecurityDescriptorLength(psd); | ||
869 | *ppsd = static_cast<SECURITY_DESCRIPTOR*>(MemAlloc(cbSD, 0)); | ||
870 | ExitOnNull(*ppsd, hr, E_OUTOFMEMORY, "failed allocate memory for security descriptor"); | ||
871 | |||
872 | memcpy(*ppsd, psd, cbSD); | ||
873 | Assert(::IsValidSecurityDescriptor(*ppsd)); | ||
874 | |||
875 | LExit: | ||
876 | if (FAILED(hr) && NULL != ppsd && NULL != *ppsd) | ||
877 | { | ||
878 | MemFree(*ppsd); | ||
879 | *ppsd = NULL; | ||
880 | } | ||
881 | |||
882 | if (psd) | ||
883 | { | ||
884 | ::LocalFree(psd); | ||
885 | } | ||
886 | |||
887 | return hr; | ||
888 | } | ||
889 | |||
890 | |||
891 | extern "C" HRESULT DAPI AclSetSecurityWithRetry( | ||
892 | __in_z LPCWSTR wzObject, | ||
893 | __in SE_OBJECT_TYPE sot, | ||
894 | __in SECURITY_INFORMATION securityInformation, | ||
895 | __in_opt PSID psidOwner, | ||
896 | __in_opt PSID psidGroup, | ||
897 | __in_opt PACL pDacl, | ||
898 | __in_opt PACL pSacl, | ||
899 | __in DWORD cRetry, | ||
900 | __in DWORD dwWaitMilliseconds | ||
901 | ) | ||
902 | { | ||
903 | HRESULT hr = S_OK; | ||
904 | LPWSTR sczObject = NULL; | ||
905 | DWORD i = 0; | ||
906 | |||
907 | hr = StrAllocString(&sczObject, wzObject, 0); | ||
908 | ExitOnFailure(hr, "Failed to copy object to secure."); | ||
909 | |||
910 | hr = E_FAIL; | ||
911 | for (i = 0; FAILED(hr) && i <= cRetry; ++i) | ||
912 | { | ||
913 | if (0 < i) | ||
914 | { | ||
915 | ::Sleep(dwWaitMilliseconds); | ||
916 | } | ||
917 | |||
918 | DWORD er = ::SetNamedSecurityInfoW(sczObject, sot, securityInformation, psidOwner, psidGroup, pDacl, pSacl); | ||
919 | hr = HRESULT_FROM_WIN32(er); | ||
920 | } | ||
921 | ExitOnRootFailure(hr, "Failed to set security on object '%ls' after %u retries.", wzObject, i); | ||
922 | |||
923 | LExit: | ||
924 | ReleaseStr(sczObject); | ||
925 | |||
926 | return hr; | ||
927 | } | ||
928 | |||
929 | |||
930 | /******************************************************************** | ||
931 | AclFreeSid - frees a SID created by any Acl* functions | ||
932 | |||
933 | ********************************************************************/ | ||
934 | extern "C" HRESULT DAPI AclFreeSid( | ||
935 | __in PSID psid | ||
936 | ) | ||
937 | { | ||
938 | Assert(psid && ::IsValidSid(psid)); | ||
939 | HRESULT hr = S_OK; | ||
940 | |||
941 | hr = MemFree(psid); | ||
942 | |||
943 | return hr; | ||
944 | } | ||
945 | |||
946 | |||
947 | /******************************************************************** | ||
948 | AclFreeDacl - frees a DACL created by any Acl* functions | ||
949 | |||
950 | ********************************************************************/ | ||
951 | extern "C" HRESULT DAPI AclFreeDacl( | ||
952 | __in ACL* pACL | ||
953 | ) | ||
954 | { | ||
955 | Assert(pACL); | ||
956 | HRESULT hr = S_OK; | ||
957 | |||
958 | hr = MemFree(pACL); | ||
959 | |||
960 | return hr; | ||
961 | } | ||
962 | |||
963 | |||
964 | /******************************************************************** | ||
965 | AclFreeSecurityDescriptor - frees a security descriptor created by any Acl* functions | ||
966 | |||
967 | ********************************************************************/ | ||
968 | extern "C" HRESULT DAPI AclFreeSecurityDescriptor( | ||
969 | __in SECURITY_DESCRIPTOR* psd | ||
970 | ) | ||
971 | { | ||
972 | Assert(psd && ::IsValidSecurityDescriptor(psd)); | ||
973 | HRESULT hr = S_OK; | ||
974 | |||
975 | hr = MemFree(psd); | ||
976 | |||
977 | return hr; | ||
978 | } | ||
979 | |||
980 | |||
981 | /******************************************************************** | ||
982 | AclAddAdminToSecurityDescriptor - Adds the Administrators group to a security descriptor | ||
983 | |||
984 | ********************************************************************/ | ||
985 | extern "C" HRESULT DAPI AclAddAdminToSecurityDescriptor( | ||
986 | __in SECURITY_DESCRIPTOR* pSecurity, | ||
987 | __deref_out SECURITY_DESCRIPTOR** ppSecurityNew | ||
988 | ) | ||
989 | { | ||
990 | HRESULT hr = S_OK; | ||
991 | PACL pAcl = NULL; | ||
992 | PACL pAclNew = NULL; | ||
993 | BOOL fValid, fDaclDefaulted; | ||
994 | ACL_ACE ace[1]; | ||
995 | SECURITY_DESCRIPTOR* pSecurityNew; | ||
996 | |||
997 | if (!::GetSecurityDescriptorDacl(pSecurity, &fValid, &pAcl, &fDaclDefaulted) || !fValid) | ||
998 | { | ||
999 | ExitOnLastError(hr, "Failed to get acl from security descriptor"); | ||
1000 | } | ||
1001 | |||
1002 | hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &ace[0].psid); | ||
1003 | ExitOnFailure(hr, "failed to get sid for Administrators group"); | ||
1004 | |||
1005 | ace[0].dwFlags = NO_PROPAGATE_INHERIT_ACE; | ||
1006 | ace[0].dwMask = GENERIC_ALL; | ||
1007 | |||
1008 | hr = AclAddToDacl(pAcl, NULL, 0, ace, 1, &pAclNew); | ||
1009 | ExitOnFailure(hr, "failed to add Administrators ACE to ACL"); | ||
1010 | |||
1011 | hr = AclCreateSecurityDescriptorFromDacl(pAclNew, &pSecurityNew); | ||
1012 | ExitOnLastError(hr, "Failed to create new security descriptor"); | ||
1013 | |||
1014 | // The DACL is referenced by, not copied into, the security descriptor. Make sure not to free it. | ||
1015 | pAclNew = NULL; | ||
1016 | |||
1017 | *ppSecurityNew = pSecurityNew; | ||
1018 | |||
1019 | LExit: | ||
1020 | if (pAclNew) | ||
1021 | { | ||
1022 | AclFreeDacl(pAclNew); | ||
1023 | } | ||
1024 | if (ace[0].psid) | ||
1025 | { | ||
1026 | AclFreeSid(ace[0].psid); | ||
1027 | } | ||
1028 | |||
1029 | return hr; | ||
1030 | } | ||