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