aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/aclutil.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-09-03 11:22:38 -0700
committerRob Mensching <rob@firegiant.com>2017-09-03 13:33:33 -0700
commit5d8375007754101ff2889d0e79486c8f9b7cf5ab (patch)
treea76d6fb6a38dd9f04a93ffcfd9d64e76779b3414 /src/dutil/aclutil.cpp
parent8e8da6dbc051ec884b5d439bb4f44dc027d05bbf (diff)
downloadwix-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.cpp1030
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/********************************************************************
6AclCheckAccess - determines if token has appropriate privileges
7
8NOTE: paa->fDenyAccess and paa->dwAccessMask are ignored and must be zero
9if hToken is NULL, the thread will be checked
10if hToken is not NULL the token must be an impersonation token
11********************************************************************/
12extern "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
44LExit:
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/********************************************************************
55AclCheckAdministratorAccess - determines if token has Administrator privileges
56
57NOTE: if hToken is NULL, the thread will be checked
58if hToken is not NULL the token must be an impersonation token
59********************************************************************/
60extern "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/********************************************************************
78AclCheckLocalSystemAccess - determines if token has LocalSystem privileges
79
80NOTE: if hToken is NULL, the thread will be checked
81if hToken is not NULL the token must be an impersonation token
82********************************************************************/
83extern "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/********************************************************************
100AclGetWellKnownSid - returns a SID for the specified account
101
102********************************************************************/
103extern "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));
183LExit:
184 if (psidTemp)
185 {
186 ::FreeSid(psidTemp);
187 }
188
189 ReleaseMem(psid);
190
191 return hr;
192}
193
194
195/********************************************************************
196AclGetAccountSid - returns a SID for the specified account
197
198********************************************************************/
199extern "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;
260LExit:
261 ReleaseStr(pwzDomainName);
262 ReleaseMem(psid);
263
264 return hr;
265}
266
267
268/********************************************************************
269AclGetAccountSidString - gets a string version of the user's SID
270
271NOTE: ppwzSid should be freed with StrFree()
272********************************************************************/
273extern "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
297LExit:
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/********************************************************************
318AclCreateDacl - creates a DACL from ACL_ACE structures
319
320********************************************************************/
321extern "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);
386LExit:
387 if (pAcl)
388 {
389 AclFreeDacl(pAcl);
390 }
391
392 return hr;
393}
394
395
396/********************************************************************
397AclAddToDacl - creates a new DACL from an ACL plus new ACL_ACE structure
398
399********************************************************************/
400extern "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);
500LExit:
501 ReleaseMem(paaNewAllow);
502 ReleaseMem(paaNewDeny);
503
504 return hr;
505}
506
507
508/********************************************************************
509AclMergeDacls - creates a new DACL from two existing ACLs
510
511********************************************************************/
512extern "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/********************************************************************
531AclCreateDaclOld - creates a DACL from an ACL_ACCESS structure
532
533********************************************************************/
534extern "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
632LExit:
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/********************************************************************
658AclCreateSecurityDescriptorFromDacl - creates a self-relative security
659descriptor from an existing DACL
660
661********************************************************************/
662extern "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
703LExit:
704 if (FAILED(hr) && NULL != ppsd && NULL != *ppsd)
705 {
706 MemFree(*ppsd);
707 *ppsd = NULL;
708 }
709
710 return hr;
711}
712
713
714/********************************************************************
715AclCreateSecurityDescriptor - creates a self-relative security descriptor from an
716ACL_ACCESS structure
717
718NOTE: ppsd should be freed with AclFreeSecurityDescriptor()
719********************************************************************/
720extern "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
744LExit:
745 return hr;
746}
747
748
749/********************************************************************
750AclCreateSecurityDescriptorFromString - creates a self-relative security
751descriptor from an SDDL string
752
753NOTE: ppsd should be freed with AclFreeSecurityDescriptor()
754********************************************************************/
755extern "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
788LExit:
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/********************************************************************
806AclDuplicateSecurityDescriptor - creates a copy of a self-relative security descriptor
807
808NOTE: passed in security descriptor must be in self-relative format
809********************************************************************/
810extern "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
831LExit:
832 if (FAILED(hr) && NULL != ppsd && NULL != *ppsd)
833 {
834 MemFree(*ppsd);
835 *ppsd = NULL;
836 }
837
838 return hr;
839}
840
841
842/********************************************************************
843AclGetSecurityDescriptor - returns self-relative security descriptor for named object
844
845NOTE: free ppsd with AclFreeSecurityDescriptor()
846********************************************************************/
847extern "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
875LExit:
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
891extern "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
923LExit:
924 ReleaseStr(sczObject);
925
926 return hr;
927}
928
929
930/********************************************************************
931AclFreeSid - frees a SID created by any Acl* functions
932
933********************************************************************/
934extern "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/********************************************************************
948AclFreeDacl - frees a DACL created by any Acl* functions
949
950********************************************************************/
951extern "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/********************************************************************
965AclFreeSecurityDescriptor - frees a security descriptor created by any Acl* functions
966
967********************************************************************/
968extern "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/********************************************************************
982AclAddAdminToSecurityDescriptor - Adds the Administrators group to a security descriptor
983
984********************************************************************/
985extern "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
1019LExit:
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}