/
SecurityInformation1.cpp
450 lines (393 loc) · 14.8 KB
/
SecurityInformation1.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
//
// This file contains the definitions for all of the ISecurityInformation
// functions from CSecInfo. This got its own file because the implementation
// of ISecurityInformation is the largest of the interfaces.
//
#include "CSecInfo.h"
#include "utility.h"
#include "authz.h"
#include <stdio.h>
#include "sddl.h"
#include <string>
IFACEMETHODIMP CSecInfo::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
{
Resource *currentResource;
// SI_OBJECT_INFO: http://msdn.microsoft.com/en-us/library/windows/desktop/aa379605(v=vs.85).aspx
m_dwSIFlags = 0
| SI_ADVANCED // The "advanced" button is displayed on the basic
// security property page
| SI_EDIT_PERMS // The basic security property page always allows
// basic editing of the object's DACL
| SI_EDIT_OWNER // This lets you change the owner on the advanced page
| SI_PAGE_TITLE // Use pObjectInfo->pszPageTitle for the basic page's
// title
| SI_VIEW_ONLY // Displays a read-only version of the ACL Editor
// dialog boxes. This is required if you're
// implementing ISecurityInformation3.
| SI_EDIT_EFFECTIVE
| SI_ENABLE_EDIT_ATTRIBUTE_CONDITION
;
currentResource = m_resources[m_editingResource];
if ( currentResource->IsContainer() != FALSE)
{
// This will make ACL UI show the inheritance controls
m_dwSIFlags |= SI_CONTAINER;
}
pObjectInfo->dwFlags = m_dwSIFlags;
pObjectInfo->hInstance = 0;
pObjectInfo->pszServerName = nullptr;
// ACL Editor won't free this, so we don't need to make a copy
pObjectInfo->pszObjectName = currentResource->GetName();
pObjectInfo->pszPageTitle = L"Forums Resource Manager";
return S_OK;
}
IFACEMETHODIMP CSecInfo::GetSecurity(
SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR *ppSD,
BOOL fDefault)
{
BOOL bResult = 0;
HRESULT hr = S_OK;
DWORD errorCode = 0;
Resource *currentResource = m_resources[m_editingResource];
ULONG defaultSecurityDescriptorSize = 0;
// This may be the default SD, or it may
// be the SD on the resource we're editing
PWSTR sdToEdit = NULL;
if ( fDefault )
{
hr = AllocAndCopyString(m_defaultSecurityDescriptorSddl, &sdToEdit);
FailGracefully(hr, L"AllocAndCopyString");
}
else
{
hr = AllocAndCopyString(
const_cast<PCWSTR>(currentResource->GetSD()),
&sdToEdit);
FailGracefully(hr, L"AllocAndCopyString");
}
if (
IS_FLAG_SET(si, DACL_SECURITY_INFORMATION) ||
IS_FLAG_SET(si, OWNER_SECURITY_INFORMATION) ||
IS_FLAG_SET(si, GROUP_SECURITY_INFORMATION)
)
{
// The following function will populate the entire SD.
bResult = ConvertStringSecurityDescriptorToSecurityDescriptor(
sdToEdit,
SDDL_REVISION_1,
ppSD,
&defaultSecurityDescriptorSize);
FailGracefullyGLE(
bResult,
L"ConvertStringSecurityDescriptorToSecurityDescriptor");
}
exit_gracefully:
LocalFree(sdToEdit);
return hr;
}
IFACEMETHODIMP CSecInfo::SetSecurity(
SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR pSD)
{
BOOL bResult = 0;
DWORD errorCode = 0;
HRESULT hr = S_OK;
PACL pDestDacl = nullptr;
BOOL bDaclPresent = 0;
BOOL bDaclDefaulted = 0;
PACL pSourceDacl = nullptr;
DWORD dwSizeNeeded;
SECURITY_DESCRIPTOR_CONTROL sdControl;
DWORD dwRevision;
int parentIndex;
PSECURITY_DESCRIPTOR pSDOfParent;
PSID group;
BOOL bGroupDefaulted = 0;
PSID owner;
BOOL bOwnerDefaulted = 0;
PWSTR stringSD;
ULONG stringSDLen = 0;
SECURITY_DESCRIPTOR_CONTROL currentObjectSDControl;
PSECURITY_DESCRIPTOR absoluteCurrentSD;
Resource *currentResource = m_resources[m_editingResource];
hr = ConvertStringToAbsSD(currentResource->GetSD(), &absoluteCurrentSD);
FailGracefully(hr, L"ConvertStringToAbsSD");
if ( IS_FLAG_SET(si, DACL_SECURITY_INFORMATION) )
{
bResult = GetSecurityDescriptorDacl(
pSD,
&bDaclPresent,
&pSourceDacl,
&bDaclDefaulted
);
FailGracefullyGLE(bResult, L"GetSecurityDescriptorDacl");
bResult = GetSecurityDescriptorDacl(
absoluteCurrentSD,
&bDaclPresent,
&pDestDacl,
&bDaclDefaulted
);
FailGracefullyGLE(bResult, L"GetSecurityDescriptorDacl");
if ( pDestDacl == nullptr )
{
// Align sizeNeeded to a DWORD
dwSizeNeeded = (sizeof(ACL) + (sizeof(DWORD) - 1)) & 0xfffffffc;
pDestDacl = (PACL)LocalAlloc(LPTR, dwSizeNeeded);
if ( pDestDacl == nullptr )
{
wprintf(L"LocalAlloc failed.\n");
hr = E_OUTOFMEMORY;
goto exit_gracefully;
}
bResult = InitializeAcl(pDestDacl, dwSizeNeeded, ACL_REVISION);
FailGracefullyGLE(bResult, L"InitializeAcl");
}
// Before doing anything else, we need to change the protected
// bit in case we end up reenabling inheritance.
// If the 'P' flag was set, e.g. D:PAR(A;CIIO;FA;;;WD)
// then we need to remove all inherited entries
bResult = GetSecurityDescriptorControl(
pSD,
&sdControl,
&dwRevision
);
FailGracefullyGLE(bResult, L"GetSecurityDescriptorControl");
bResult = GetSecurityDescriptorControl(
absoluteCurrentSD,
¤tObjectSDControl,
&dwRevision
);
FailGracefullyGLE(bResult, L"GetSecurityDescriptorControl");
BOOL currentObjectWasProtected =
IS_FLAG_SET(currentObjectSDControl, SE_DACL_PROTECTED)
? TRUE
: FALSE;
// Now that we've gotten the SE_DACL_PROTECTED bit off of the current
// object, we can set it to what it needs to be. We needed to capture
// it in the case that we're reenabling inheritance.
bResult = SetSecurityDescriptorControl(
absoluteCurrentSD,
SE_DACL_PROTECTED,
IS_FLAG_SET(sdControl, SE_DACL_PROTECTED)
? SE_DACL_PROTECTED
: 0
);
FailGracefullyGLE(bResult, L"SetSecurityDescriptorControl");
if ( IS_FLAG_SET(sdControl, SE_DACL_PROTECTED) )
{
hr = RemoveAllInheritedAces(
&pDestDacl
);
FailGracefully(hr, L"RemoveAllInheritedAces");
}
else
{
// The user reenabled inheritance (i.e. didn't pass in
// SE_DACL_PROTECTED, but the object used to have that flag).
if ( currentObjectWasProtected != FALSE )
{
// This means we need to call SetSecurityOfChildren on the
// parent. This is why we disabled the SE_DACL_PROTECTED flag
// already - otherwise the function would exit immediately.
parentIndex = currentResource->GetParentIndex();
if ( parentIndex != NONEXISTENT_OBJECT )
{
Resource *parentResource = m_resources[parentIndex];
// Because we're keeping SDs as strings, we need to do
// a bit of hackery here to set up for SetSecurityOfChildren.
// First, save the current security descriptor to where
// SetSecurityOfChildren can pick it up
{
bResult = ConvertSecurityDescriptorToStringSecurityDescriptor(
absoluteCurrentSD,
SDDL_REVISION_1,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION |
LABEL_SECURITY_INFORMATION |
ATTRIBUTE_SECURITY_INFORMATION |
SCOPE_SECURITY_INFORMATION,
&stringSD,
&stringSDLen
);
FailGracefullyGLE(bResult, L"ConvertSecurityDescriptorToStringSecurityDescriptor");
currentResource->FreeSD();
currentResource->SetSD(stringSD);
stringSD = nullptr;
}
hr = ConvertStringToAbsSD(
parentResource->GetSD(),
&pSDOfParent);
FailGracefully(hr, L"ConvertStringToAbsSD");
hr = SetSecurityOfChildren(
parentIndex,
DACL_SECURITY_INFORMATION,
pSDOfParent);
FailGracefully(hr, L"SetSecurityOfChildren");
// Now, the current resource's SD will be set to what we want...
// so we need to make sure we're working on that by making
// absoluteCurrentSD into that.
hr = ConvertStringToAbsSD(
currentResource->GetSD(),
&absoluteCurrentSD);
FailGracefully(hr, L"ConvertStringToAbsSD");
// The DACL probably just changed
bResult = GetSecurityDescriptorDacl(
absoluteCurrentSD,
&bDaclPresent,
&pDestDacl,
&bDaclDefaulted
);
FailGracefullyGLE(bResult, L"GetSecurityDescriptorDacl");
}
}
}
hr = AddAllAcesFromAcl(pSourceDacl, &pDestDacl, TRUE);
FailGracefully(hr, L"AddAllAcesFromAcl");
// Finally, remove the explicit ACEs that don't appear in pSD.
// These are ACEs that used to be on the DACL, but the user just
// removed.
hr = RemoveExplicitUniqueAces(
pSourceDacl,
&pDestDacl
);
FailGracefully(hr, L"RemoveExplicitUniqueAces");
hr = OrderDacl(
m_editingResource,
&pDestDacl
);
FailGracefully(hr, L"OrderDacl");
bResult = SetSecurityDescriptorDacl(
absoluteCurrentSD,
true,
pDestDacl,
bDaclDefaulted
);
FailGracefullyGLE(bResult, L"SetSecurityDescriptorDacl");
pDestDacl = nullptr;
}
if ( IS_FLAG_SET(si, GROUP_SECURITY_INFORMATION) )
{
bResult = GetSecurityDescriptorGroup(
pSD,
&group,
&bGroupDefaulted
);
FailGracefullyGLE(bResult, L"GetSecurityDescriptorGroup");
bResult = SetSecurityDescriptorGroup(
absoluteCurrentSD,
group,
bGroupDefaulted
);
FailGracefullyGLE(bResult, L"SetSecurityDescriptorGroup");
}
if ( IS_FLAG_SET(si, OWNER_SECURITY_INFORMATION) )
{
bResult = GetSecurityDescriptorOwner(
pSD,
&owner,
&bOwnerDefaulted
);
FailGracefullyGLE(bResult, L"GetSecurityDescriptorOwner");
bResult = SetSecurityDescriptorOwner(
absoluteCurrentSD,
owner,
bOwnerDefaulted
);
FailGracefullyGLE(bResult, L"SetSecurityDescriptorOwner");
}
// Finally, convert whatever changes we made to the absolute SD back to a string
bResult = ConvertSecurityDescriptorToStringSecurityDescriptor(
absoluteCurrentSD,
SDDL_REVISION_1,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION |
LABEL_SECURITY_INFORMATION |
ATTRIBUTE_SECURITY_INFORMATION |
SCOPE_SECURITY_INFORMATION,
&stringSD,
&stringSDLen
);
FailGracefullyGLE(bResult, L"ConvertSecurityDescriptorToStringSecurityDescriptor");
currentResource->FreeSD();
currentResource->SetSD(stringSD);
stringSD = nullptr;
if ( currentResource->IsContainer() != FALSE)
{
hr = SetSecurityOfChildren(m_editingResource, si, absoluteCurrentSD);
FailGracefully(hr, L"SetSecurityOfChildren");
}
exit_gracefully:
LocalFree(pDestDacl);
return hr;
}
IFACEMETHODIMP CSecInfo::GetAccessRights(
const GUID* pguidObjectType,
DWORD dwFlags,
PSI_ACCESS *ppAccess,
ULONG *pcAccesses,
ULONG *piDefaultAccess)
{
UNREFERENCED_PARAMETER(dwFlags);
if ( pguidObjectType == nullptr || *pguidObjectType == GUID_NULL )
{
*ppAccess = const_cast<SI_ACCESS *>(m_AccessTable);
*pcAccesses = m_AccessTableCount;
// This is the index of the default access you want when you're
// adding a permission. It ends up indexing m_AccessTable, which
// is really g_siForumsAccess, so 0 is Full Control.
*piDefaultAccess = m_DefaultAccess;
}
return S_OK;
}
// This function requests that the generic access rights in an access mask
// be mapped to their corresponding standard and specific access rights.
IFACEMETHODIMP CSecInfo::MapGeneric(
const GUID *pguidObjectType,
UCHAR *pAceFlags,
ACCESS_MASK *pMask)
{
if ( !pAceFlags || !pMask )
{
return E_INVALIDARG;
}
// This sample doesn't include object inheritance, so that bit can be
// safely removed.
*pAceFlags &= ~OBJECT_INHERIT_ACE;
MapGenericMask(pMask, &ObjectMap);
UNREFERENCED_PARAMETER(pguidObjectType);
return S_OK;
}
IFACEMETHODIMP CSecInfo::GetInheritTypes(
PSI_INHERIT_TYPE *ppInheritTypes,
ULONG *pcInheritTypes)
{
if ( m_resources[m_editingResource]->IsContainer() != FALSE)
{
*ppInheritTypes = siSDKInheritTypes;
*pcInheritTypes = ARRAYSIZE(siSDKInheritTypes);
return S_OK;
}
return E_NOTIMPL;
}
IFACEMETHODIMP CSecInfo::PropertySheetPageCallback(
HWND hwnd,
UINT uMsg,
SI_PAGE_TYPE uPage)
{
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(uPage);
return E_NOTIMPL;
}