1 /*
2  * Regedit ACL Editor for Registry Keys
3  *
4  * Copyright (C) 2004-2006 Thomas Weidenmueller <w3seek@reactos.com>
5  * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
6  */
7 
8 #include "regedit.h"
9 
10 #define INITGUID
11 #include <guiddef.h>
12 
13 /* FIXME - shouldn't be defined here... */
14 DEFINE_GUID(IID_IRegKeySecurity, 0x965fc360, 0x16ff, 0x11d0, 0x0091, 0xcb,0x00,0xaa,0x00,0xbb,0xb7,0x23);
15 #if REGEDIT_IMPLEMENT_ISECURITYINFORMATION2
16 DEFINE_GUID(IID_IRegKeySecurity2, 0xc3ccfdb4, 0x6f88, 0x11d2, 0x00a3, 0xce,0x00,0xc0,0x4f,0xb1,0x78,0x2a);
17 #endif
18 
19 /* FIXME: already defined in aclui.h - causing problems when compiling with MSVC/PSDK*/
20 #ifdef _MSC_VER
21 #pragma message ("INVESTIGATE ME")
22 #endif
23 
24 #if 1 //#ifndef _MSC_VER
25 DEFINE_GUID(IID_IEffectivePermission, 0x3853dc76, 0x9f35, 0x407c, 0x0088, 0xa1,0xd1,0x93,0x44,0x36,0x5f,0xbc);
26 DEFINE_GUID(IID_ISecurityObjectTypeInfo, 0xfc3066eb, 0x79ef, 0x444b, 0x0091, 0x11,0xd1,0x8a,0x75,0xeb,0xf2,0xfa);
27 #endif
28 
29 /******************************************************************************
30    Implementation of the IUnknown methods of CRegKeySecurity
31  ******************************************************************************/
32 
33 static __inline PCRegKeySecurity
34 impl_from_ISecurityInformation(struct ISecurityInformation *iface)
35 {
36     return (PCRegKeySecurity)((ULONG_PTR)iface - FIELD_OFFSET(CRegKeySecurity,
37                                                               lpISecurityInformationVtbl));
38 }
39 
40 #if REGEDIT_IMPLEMENT_ISECURITYINFORMATION2
41 static __inline PCRegKeySecurity
42 impl_from_ISecurityInformation2(struct ISecurityInformation2 *iface)
43 {
44     return (PCRegKeySecurity)((ULONG_PTR)iface - FIELD_OFFSET(CRegKeySecurity,
45                                                               lpISecurityInformation2Vtbl));
46 }
47 #endif
48 
49 static __inline PCRegKeySecurity
50 impl_from_ISecurityObjectTypeInfo(struct ISecurityObjectTypeInfo *iface)
51 {
52     return (PCRegKeySecurity)((ULONG_PTR)iface - FIELD_OFFSET(CRegKeySecurity,
53                                                               lpISecurityObjectTypeInfoVtbl));
54 }
55 
56 static __inline PCRegKeySecurity
57 impl_from_IEffectivePermission(struct IEffectivePermission *iface)
58 {
59     return (PCRegKeySecurity)((ULONG_PTR)iface - FIELD_OFFSET(CRegKeySecurity,
60                                                               lpIEffectivePermissionVtbl));
61 }
62 
63 #define impl_to_interface(impl,iface) (struct iface *)(&(impl)->lp##iface##Vtbl)
64 
65 static __inline ULONG
66 CRegKeySecurity_fnAddRef(PCRegKeySecurity obj)
67 {
68     return (ULONG)InterlockedIncrement((LONG*)&obj->ref);
69 }
70 
71 static __inline ULONG
72 CRegKeySecurity_fnRelease(PCRegKeySecurity obj)
73 {
74     ULONG Ret;
75 
76     Ret = (ULONG)InterlockedDecrement((LONG*)&obj->ref);
77     if (Ret == 0)
78     {
79         HeapFree(GetProcessHeap(), 0, obj);
80     }
81 
82     return Ret;
83 }
84 
85 static __inline HRESULT
86 CRegKeySecurity_fnQueryInterface(PCRegKeySecurity obj,
87                                  REFIID iid,
88                                  PVOID *pvObject)
89 {
90     PVOID pvObj = NULL;
91 
92     if (IsEqualGUID(iid, &IID_IRegKeySecurity))
93     {
94         pvObj = (PVOID)impl_to_interface(obj, ISecurityInformation);
95     }
96 #if REGEDIT_IMPLEMENT_ISECURITYINFORMATION2
97     else if (IsEqualGUID(iid, &IID_IRegKeySecurity2))
98     {
99         pvObj = (PVOID)impl_to_interface(obj, ISecurityInformation2);
100     }
101 #endif
102     else if (IsEqualGUID(iid, &IID_IEffectivePermission))
103     {
104         pvObj = (PVOID)impl_to_interface(obj, IEffectivePermission);
105     }
106     else if (IsEqualGUID(iid, &IID_ISecurityObjectTypeInfo))
107     {
108         pvObj = (PVOID)impl_to_interface(obj, ISecurityObjectTypeInfo);
109     }
110 
111     if (pvObj == NULL)
112     {
113         return E_NOINTERFACE;
114     }
115 
116     *pvObject = pvObj;
117     CRegKeySecurity_fnAddRef(obj);
118 
119     return S_OK;
120 }
121 
122 
123 /******************************************************************************
124    Definition of the ISecurityInformation interface
125  ******************************************************************************/
126 
127 /* IUnknown */
128 static HRESULT STDMETHODCALLTYPE
129 ISecurityInformation_fnQueryInterface(struct ISecurityInformation *this,
130                                       REFIID iid,
131                                       PVOID *pvObject);
132 
133 static ULONG STDMETHODCALLTYPE
134 ISecurityInformation_fnAddRef(struct ISecurityInformation *this);
135 
136 static ULONG STDMETHODCALLTYPE
137 ISecurityInformation_fnRelease(struct ISecurityInformation *this);
138 
139 /* ISecurityInformation */
140 static HRESULT STDMETHODCALLTYPE
141 ISecurityInformation_fnGetObjectInformation(struct ISecurityInformation *this,
142                                             PSI_OBJECT_INFO pObjectInfo);
143 
144 static HRESULT STDMETHODCALLTYPE
145 ISecurityInformation_fnGetSecurity(struct ISecurityInformation *this,
146                                    SECURITY_INFORMATION RequestedInformation,
147                                    PSECURITY_DESCRIPTOR* ppSecurityDescriptor,
148                                    BOOL fDefault);
149 
150 static HRESULT STDMETHODCALLTYPE
151 ISecurityInformation_fnSetSecurity(struct ISecurityInformation *this,
152                                    SECURITY_INFORMATION RequestedInformation,
153                                    PSECURITY_DESCRIPTOR pSecurityDescriptor);
154 
155 static HRESULT STDMETHODCALLTYPE
156 ISecurityInformation_fnGetAccessRights(struct ISecurityInformation *this,
157                                        const GUID* pguidObjectType,
158                                       DWORD dwFlags,
159                                       PSI_ACCESS* ppAccess,
160                                       ULONG* pcAccesses,
161                                       ULONG* piDefaultAccess);
162 
163 static HRESULT STDMETHODCALLTYPE
164 ISecurityInformation_fnMapGeneric(struct ISecurityInformation *this,
165                                  const GUID* pguidObjectType,
166                                  UCHAR* pAceFlags,
167                                  ACCESS_MASK* pMask);
168 
169 static HRESULT STDMETHODCALLTYPE
170 ISecurityInformation_fnGetInheritTypes(struct ISecurityInformation *this,
171                                       PSI_INHERIT_TYPE* ppInheritTypes,
172                                       ULONG* pcInheritTypes);
173 static HRESULT STDMETHODCALLTYPE
174 ISecurityInformation_fnPropertySheetPageCallback(struct ISecurityInformation *this,
175                                                 HWND hwnd,
176                                                 UINT uMsg,
177                                                 SI_PAGE_TYPE uPage);
178 
179 static const struct ifaceISecurityInformationVbtl vtblISecurityInformation =
180 {
181     /* IUnknown methods */
182     ISecurityInformation_fnQueryInterface,
183     ISecurityInformation_fnAddRef,
184     ISecurityInformation_fnRelease,
185 
186     /* ISecurityInformation methods */
187     ISecurityInformation_fnGetObjectInformation,
188     ISecurityInformation_fnGetSecurity,
189     ISecurityInformation_fnSetSecurity,
190     ISecurityInformation_fnGetAccessRights,
191     ISecurityInformation_fnMapGeneric,
192     ISecurityInformation_fnGetInheritTypes,
193     ISecurityInformation_fnPropertySheetPageCallback,
194 };
195 
196 #if REGEDIT_IMPLEMENT_ISECURITYINFORMATION2
197 /******************************************************************************
198    Definition of the ISecurityInformation2 interface
199  ******************************************************************************/
200 
201 /* IUnknown */
202 static HRESULT STDMETHODCALLTYPE
203 ISecurityInformation2_fnQueryInterface(struct ISecurityInformation2 *this,
204                                        REFIID iid,
205                                        PVOID *pvObject);
206 
207 static ULONG STDMETHODCALLTYPE
208 ISecurityInformation2_fnAddRef(struct ISecurityInformation2 *this);
209 
210 static ULONG STDMETHODCALLTYPE
211 ISecurityInformation2_fnRelease(struct ISecurityInformation2 *this);
212 
213 /* ISecurityInformation2 */
214 static BOOL STDMETHODCALLTYPE
215 ISecurityInformation2_fnIsDaclCanonical(struct ISecurityInformation2 *this,
216                                         PACL pDacl);
217 
218 static HRESULT STDMETHODCALLTYPE
219 ISecurityInformation2_fnLookupSids(struct ISecurityInformation2 *this,
220                                    ULONG cSids,
221                                    PSID* rgpSids,
222                                    LPDATAOBJECT* ppdo);
223 
224 static const struct ifaceISecurityInformation2Vbtl vtblISecurityInformation2 =
225 {
226     /* IUnknown methods */
227     ISecurityInformation2_fnQueryInterface,
228     ISecurityInformation2_fnAddRef,
229     ISecurityInformation2_fnRelease,
230 
231     /* ISecurityInformation2 methods */
232     ISecurityInformation2_fnIsDaclCanonical,
233     ISecurityInformation2_fnLookupSids
234 };
235 #endif
236 
237 /******************************************************************************
238    Definition of the IEffectivePermission interface
239  ******************************************************************************/
240 
241 /* IUnknown */
242 static HRESULT STDMETHODCALLTYPE
243 IEffectivePermission_fnQueryInterface(struct IEffectivePermission *this,
244                                       REFIID iid,
245                                       PVOID *pvObject);
246 
247 static ULONG STDMETHODCALLTYPE
248 IEffectivePermission_fnAddRef(struct IEffectivePermission *this);
249 
250 static ULONG STDMETHODCALLTYPE
251 IEffectivePermission_fnRelease(struct IEffectivePermission *this);
252 
253 /* IEffectivePermission */
254 static HRESULT STDMETHODCALLTYPE
255 IEffectivePermission_fnGetEffectivePermission(struct IEffectivePermission *this,
256                                               const GUID* pguidObjectType,
257                                               PSID pUserSid,
258                                               LPCWSTR pszServerName,
259                                               PSECURITY_DESCRIPTOR pSD,
260                                               POBJECT_TYPE_LIST* ppObjectTypeList,
261                                               ULONG* pcObjectTypeListLength,
262                                               PACCESS_MASK* ppGrantedAccessList,
263                                               ULONG* pcGrantedAccessListLength);
264 
265 static const struct ifaceIEffectivePermissionVbtl vtblIEffectivePermission =
266 {
267     /* IUnknown methods */
268     IEffectivePermission_fnQueryInterface,
269     IEffectivePermission_fnAddRef,
270     IEffectivePermission_fnRelease,
271 
272     /* IEffectivePermissions methods */
273     IEffectivePermission_fnGetEffectivePermission
274 };
275 
276 /******************************************************************************
277    Definition of the ISecurityObjectTypeInfo interface
278  ******************************************************************************/
279 
280 /* IUnknown */
281 static HRESULT STDMETHODCALLTYPE
282 ISecurityObjectTypeInfo_fnQueryInterface(struct ISecurityObjectTypeInfo *this,
283                                          REFIID iid,
284                                          PVOID *pvObject);
285 
286 static ULONG STDMETHODCALLTYPE
287 ISecurityObjectTypeInfo_fnAddRef(struct ISecurityObjectTypeInfo *this);
288 
289 static ULONG STDMETHODCALLTYPE
290 ISecurityObjectTypeInfo_fnRelease(struct ISecurityObjectTypeInfo *this);
291 
292 /* ISecurityObjectTypeInfo */
293 static HRESULT STDMETHODCALLTYPE
294 ISecurityObjectTypeInfo_fnGetInheritSource(struct ISecurityObjectTypeInfo *this,
295                                            SECURITY_INFORMATION si,
296                                            PACL pACL,
297                                            PINHERITED_FROM* ppInheritArray);
298 
299 static const struct ifaceISecurityObjectTypeInfoVbtl vtblISecurityObjectTypeInfo =
300 {
301     /* IUnknown methods */
302     ISecurityObjectTypeInfo_fnQueryInterface,
303     ISecurityObjectTypeInfo_fnAddRef,
304     ISecurityObjectTypeInfo_fnRelease,
305 
306     /* ISecurityObjectTypeInfo methods */
307     ISecurityObjectTypeInfo_fnGetInheritSource
308 };
309 
310 
311 /******************************************************************************
312    Implementation of the ISecurityInformation interface
313  ******************************************************************************/
314 
315 static SI_ACCESS RegAccess[] = {
316     {&GUID_NULL, KEY_ALL_ACCESS,         MAKEINTRESOURCEW(IDS_ACCESS_FULLCONTROL),      SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC},
317     {&GUID_NULL, KEY_READ,               MAKEINTRESOURCEW(IDS_ACCESS_READ),             SI_ACCESS_GENERAL},
318     {&GUID_NULL, KEY_QUERY_VALUE,        MAKEINTRESOURCEW(IDS_ACCESS_QUERYVALUE),       SI_ACCESS_SPECIFIC},
319     {&GUID_NULL, KEY_SET_VALUE,          MAKEINTRESOURCEW(IDS_ACCESS_SETVALUE),         SI_ACCESS_SPECIFIC},
320     {&GUID_NULL, KEY_CREATE_SUB_KEY,     MAKEINTRESOURCEW(IDS_ACCESS_CREATESUBKEY),     SI_ACCESS_SPECIFIC},
321     {&GUID_NULL, KEY_ENUMERATE_SUB_KEYS, MAKEINTRESOURCEW(IDS_ACCESS_ENUMERATESUBKEYS), SI_ACCESS_SPECIFIC},
322     {&GUID_NULL, KEY_NOTIFY,             MAKEINTRESOURCEW(IDS_ACCESS_NOTIFY),           SI_ACCESS_SPECIFIC},
323     {&GUID_NULL, KEY_CREATE_LINK,        MAKEINTRESOURCEW(IDS_ACCESS_CREATELINK),       SI_ACCESS_SPECIFIC},
324     {&GUID_NULL, DELETE,                 MAKEINTRESOURCEW(IDS_ACCESS_DELETE),           SI_ACCESS_SPECIFIC},
325     {&GUID_NULL, WRITE_DAC,              MAKEINTRESOURCEW(IDS_ACCESS_WRITEDAC),         SI_ACCESS_SPECIFIC},
326     {&GUID_NULL, WRITE_OWNER,            MAKEINTRESOURCEW(IDS_ACCESS_WRITEOWNER),       SI_ACCESS_SPECIFIC},
327     {&GUID_NULL, READ_CONTROL,           MAKEINTRESOURCEW(IDS_ACCESS_READCONTROL),      SI_ACCESS_SPECIFIC},
328 };
329 
330 static const DWORD RegDefaultAccess = 1; /* KEY_READ */
331 
332 static GENERIC_MAPPING RegAccessMasks = {
333     KEY_READ,
334     KEY_WRITE,
335     KEY_EXECUTE,
336     KEY_ALL_ACCESS
337 };
338 
339 static SI_INHERIT_TYPE RegInheritTypes[] = {
340     {&GUID_NULL, 0,                                        (LPWSTR)MAKEINTRESOURCEW(IDS_INHERIT_THISKEYONLY)},
341     {&GUID_NULL, CONTAINER_INHERIT_ACE,                    (LPWSTR)MAKEINTRESOURCEW(IDS_INHERIT_THISKEYANDSUBKEYS)},
342     {&GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, (LPWSTR)MAKEINTRESOURCEW(IDS_INHERIT_SUBKEYSONLY)},
343 };
344 
345 static HRESULT STDMETHODCALLTYPE
346 ISecurityInformation_fnQueryInterface(struct ISecurityInformation *this,
347                                       REFIID iid,
348                                       PVOID *pvObject)
349 {
350     if (IsEqualGUID(iid, &IID_IUnknown))
351     {
352         *pvObject = (PVOID)this;
353         ISecurityInformation_fnAddRef(this);
354         return S_OK;
355     }
356 
357     return CRegKeySecurity_fnQueryInterface(impl_from_ISecurityInformation(this),
358                                             iid,
359                                             pvObject);
360 }
361 
362 static ULONG STDMETHODCALLTYPE
363 ISecurityInformation_fnAddRef(struct ISecurityInformation *this)
364 {
365     return CRegKeySecurity_fnAddRef(impl_from_ISecurityInformation(this));
366 }
367 
368 static ULONG STDMETHODCALLTYPE
369 ISecurityInformation_fnRelease(struct ISecurityInformation *this)
370 {
371     return CRegKeySecurity_fnRelease(impl_from_ISecurityInformation(this));
372 }
373 
374 static HRESULT STDMETHODCALLTYPE
375 ISecurityInformation_fnGetObjectInformation(struct ISecurityInformation *this,
376                                             PSI_OBJECT_INFO pObjectInfo)
377 {
378     PCRegKeySecurity obj = impl_from_ISecurityInformation(this);
379 
380     *pObjectInfo = obj->ObjectInfo;
381     return S_OK;
382 }
383 
384 static HRESULT STDMETHODCALLTYPE
385 ISecurityInformation_fnGetSecurity(struct ISecurityInformation *this,
386                                    SECURITY_INFORMATION RequestedInformation,
387                                    PSECURITY_DESCRIPTOR* ppSecurityDescriptor,
388                                    BOOL fDefault)
389 {
390     PCRegKeySecurity obj = impl_from_ISecurityInformation(this);
391     LONG ErrorCode;
392 
393     ErrorCode = GetNamedSecurityInfoW(obj->szRegKey,
394                                       SE_REGISTRY_KEY,
395                                       RequestedInformation,
396                                       NULL,
397                                       NULL,
398                                       NULL,
399                                       NULL,
400                                       ppSecurityDescriptor);
401 
402     return HRESULT_FROM_WIN32(ErrorCode);
403 }
404 
405 static HRESULT STDMETHODCALLTYPE
406 ISecurityInformation_fnSetSecurity(struct ISecurityInformation *this,
407                                    SECURITY_INFORMATION RequestedInformation,
408                                    PSECURITY_DESCRIPTOR pSecurityDescriptor)
409 {
410     PCRegKeySecurity obj = impl_from_ISecurityInformation(this);
411 
412     /* FIXME */
413     *obj->Btn = TRUE;
414     return S_OK;
415 }
416 
417 static HRESULT STDMETHODCALLTYPE
418 ISecurityInformation_fnGetAccessRights(struct ISecurityInformation *this,
419                                        const GUID* pguidObjectType,
420                                        DWORD dwFlags,
421                                        PSI_ACCESS* ppAccess,
422                                        ULONG* pcAccesses,
423                                        ULONG* piDefaultAccess)
424 {
425     *ppAccess = RegAccess;
426     *pcAccesses = ARRAY_SIZE(RegAccess);
427     *piDefaultAccess = RegDefaultAccess;
428     return S_OK;
429 }
430 
431 static HRESULT STDMETHODCALLTYPE
432 ISecurityInformation_fnMapGeneric(struct ISecurityInformation *this,
433                                   const GUID* pguidObjectType,
434                                   UCHAR* pAceFlags,
435                                   ACCESS_MASK* pMask)
436 {
437     MapGenericMask(pMask, &RegAccessMasks);
438     *pMask &= ~SYNCHRONIZE;
439     return S_OK;
440 }
441 
442 static HRESULT STDMETHODCALLTYPE
443 ISecurityInformation_fnGetInheritTypes(struct ISecurityInformation *this,
444                                        PSI_INHERIT_TYPE* ppInheritTypes,
445                                        ULONG* pcInheritTypes)
446 {
447     PCRegKeySecurity obj = impl_from_ISecurityInformation(this);
448 
449     /* FIXME */
450     if (obj->ObjectInfo.dwFlags & SI_CONTAINER)
451     {
452         *ppInheritTypes = RegInheritTypes;
453         *pcInheritTypes = ARRAY_SIZE(RegInheritTypes);
454         return S_OK;
455     }
456 
457     return E_NOTIMPL;
458 }
459 
460 static HRESULT STDMETHODCALLTYPE
461 ISecurityInformation_fnPropertySheetPageCallback(struct ISecurityInformation *this,
462     HWND hwnd,
463     UINT uMsg,
464     SI_PAGE_TYPE uPage)
465 {
466     return S_OK;
467 }
468 
469 #if REGEDIT_IMPLEMENT_ISECURITYINFORMATION2
470 /******************************************************************************
471    Implementation of the ISecurityInformation2 interface
472  ******************************************************************************/
473 
474 static HRESULT STDMETHODCALLTYPE
475 ISecurityInformation2_fnQueryInterface(struct ISecurityInformation2 *this,
476                                        REFIID iid,
477                                        PVOID *pvObject)
478 {
479     if (IsEqualGUID(iid, &IID_IUnknown))
480     {
481         *pvObject = (PVOID)this;
482         ISecurityInformation2_fnAddRef(this);
483         return S_OK;
484     }
485 
486     return CRegKeySecurity_fnQueryInterface(impl_from_ISecurityInformation2(this),
487                                             iid,
488                                             pvObject);
489 }
490 
491 static ULONG STDMETHODCALLTYPE
492 ISecurityInformation2_fnAddRef(struct ISecurityInformation2 *this)
493 {
494     return CRegKeySecurity_fnAddRef(impl_from_ISecurityInformation2(this));
495 }
496 
497 static ULONG STDMETHODCALLTYPE
498 ISecurityInformation2_fnRelease(struct ISecurityInformation2 *this)
499 {
500     return CRegKeySecurity_fnRelease(impl_from_ISecurityInformation2(this));
501 }
502 
503 static BOOL STDMETHODCALLTYPE
504 ISecurityInformation2_fnIsDaclCanonical(struct ISecurityInformation2 *this,
505                                         PACL pDacl)
506 {
507     /* FIXME */
508     return TRUE;
509 }
510 
511 static HRESULT STDMETHODCALLTYPE
512 ISecurityInformation2_fnLookupSids(struct ISecurityInformation2 *this,
513                                    ULONG cSids,
514                                    PSID* rgpSids,
515                                    LPDATAOBJECT* ppdo)
516 {
517     /* FIXME */
518     return E_NOTIMPL;
519 }
520 #endif
521 
522 /******************************************************************************
523    Implementation of the IEffectivePermission interface
524  ******************************************************************************/
525 
526 static HRESULT STDMETHODCALLTYPE
527 IEffectivePermission_fnQueryInterface(struct IEffectivePermission *this,
528                                       REFIID iid,
529                                       PVOID *pvObject)
530 {
531     if (IsEqualGUID(iid, &IID_IUnknown))
532     {
533         *pvObject = (PVOID)this;
534         IEffectivePermission_fnAddRef(this);
535         return S_OK;
536     }
537 
538     return CRegKeySecurity_fnQueryInterface(impl_from_IEffectivePermission(this),
539                                             iid,
540                                             pvObject);
541 }
542 
543 static ULONG STDMETHODCALLTYPE
544 IEffectivePermission_fnAddRef(struct IEffectivePermission *this)
545 {
546     return CRegKeySecurity_fnAddRef(impl_from_IEffectivePermission(this));
547 }
548 
549 static ULONG STDMETHODCALLTYPE
550 IEffectivePermission_fnRelease(struct IEffectivePermission *this)
551 {
552     return CRegKeySecurity_fnRelease(impl_from_IEffectivePermission(this));
553 }
554 
555 static HRESULT STDMETHODCALLTYPE
556 IEffectivePermission_fnGetEffectivePermission(struct IEffectivePermission *this,
557                                               const GUID* pguidObjectType,
558                                               PSID pUserSid,
559                                               LPCWSTR pszServerName,
560                                               PSECURITY_DESCRIPTOR pSD,
561                                               POBJECT_TYPE_LIST* ppObjectTypeList,
562                                               ULONG* pcObjectTypeListLength,
563                                               PACCESS_MASK* ppGrantedAccessList,
564                                               ULONG* pcGrantedAccessListLength)
565 {
566     PACL Dacl = NULL;
567     BOOL DaclPresent, DaclDefaulted;
568     PACCESS_MASK GrantedAccessList;
569     DWORD ErrorCode = ERROR_SUCCESS;
570     TRUSTEE Trustee = {0};
571     static OBJECT_TYPE_LIST DefObjTypeList = {0};
572 
573     *ppObjectTypeList = &DefObjTypeList;
574     *pcObjectTypeListLength = 1;
575 
576     BuildTrusteeWithSid(&Trustee, pUserSid);
577 
578     if (GetSecurityDescriptorDacl(pSD,
579                                   &DaclPresent,
580                                   &Dacl,
581                                   &DaclDefaulted) && DaclPresent)
582     {
583         GrantedAccessList = (PACCESS_MASK)LocalAlloc(LMEM_FIXED,
584                                                      sizeof(ACCESS_MASK));
585         if (GrantedAccessList == NULL)
586         {
587             goto Fail;
588         }
589 
590         ErrorCode = GetEffectiveRightsFromAcl(Dacl,
591                                               &Trustee,
592                                               GrantedAccessList);
593         if (ErrorCode == ERROR_SUCCESS)
594         {
595             *ppGrantedAccessList = GrantedAccessList;
596             *pcGrantedAccessListLength = 1;
597         }
598         else
599             LocalFree((HLOCAL)GrantedAccessList);
600     }
601     else
602 Fail:
603         ErrorCode = GetLastError();
604 
605     return HRESULT_FROM_WIN32(ErrorCode);
606 }
607 
608 /******************************************************************************
609    Implementation of the ISecurityObjectTypeInfo interface
610  ******************************************************************************/
611 
612 static HRESULT STDMETHODCALLTYPE
613 ISecurityObjectTypeInfo_fnQueryInterface(struct ISecurityObjectTypeInfo *this,
614                                          REFIID iid,
615                                          PVOID *pvObject)
616 {
617     if (IsEqualGUID(iid, &IID_IUnknown))
618     {
619         *pvObject = (PVOID)this;
620         ISecurityObjectTypeInfo_fnAddRef(this);
621         return S_OK;
622     }
623 
624     return CRegKeySecurity_fnQueryInterface(impl_from_ISecurityObjectTypeInfo(this),
625                                             iid,
626                                             pvObject);
627 }
628 
629 static ULONG STDMETHODCALLTYPE
630 ISecurityObjectTypeInfo_fnAddRef(struct ISecurityObjectTypeInfo *this)
631 {
632     return CRegKeySecurity_fnAddRef(impl_from_ISecurityObjectTypeInfo(this));
633 }
634 
635 static ULONG STDMETHODCALLTYPE
636 ISecurityObjectTypeInfo_fnRelease(struct ISecurityObjectTypeInfo *this)
637 {
638     return CRegKeySecurity_fnRelease(impl_from_ISecurityObjectTypeInfo(this));
639 }
640 
641 static HRESULT STDMETHODCALLTYPE
642 ISecurityObjectTypeInfo_fnGetInheritSource(struct ISecurityObjectTypeInfo *this,
643                                            SECURITY_INFORMATION si,
644                                            PACL pACL,
645                                            PINHERITED_FROM* ppInheritArray)
646 {
647     PCRegKeySecurity obj = impl_from_ISecurityObjectTypeInfo(this);
648     PINHERITED_FROM pif, pif2;
649     SIZE_T pifSize;
650     DWORD ErrorCode, i;
651     LPWSTR lpBuf;
652 
653     pifSize = pACL->AceCount * sizeof(INHERITED_FROM);
654     pif = (PINHERITED_FROM)HeapAlloc(GetProcessHeap(), 0, pifSize);
655     if (pif == NULL)
656         return E_OUTOFMEMORY;
657 
658     ErrorCode = GetInheritanceSourceW(obj->szRegKey,
659                                       SE_REGISTRY_KEY,
660                                       si,
661                                       (obj->ObjectInfo.dwFlags & SI_CONTAINER) != 0,
662                                       NULL,
663                                       0,
664                                       pACL,
665                                       NULL,
666                                       &RegAccessMasks,
667                                       pif);
668     if (ErrorCode == ERROR_SUCCESS)
669     {
670         /* Calculate the size of the buffer to return */
671         for (i = 0; i < pACL->AceCount; i++)
672         {
673             if (pif[i].AncestorName != NULL)
674                 pifSize += (wcslen(pif[i].AncestorName) + 1) * sizeof(WCHAR);
675         }
676 
677         /* Allocate enough space for the array and the strings */
678         pif2 = (PINHERITED_FROM)LocalAlloc(LMEM_FIXED, pifSize);
679         if (pif2 == NULL)
680         {
681             ErrorCode = GetLastError();
682             goto Cleanup;
683         }
684 
685         /* copy the array and strings to the buffer */
686         lpBuf = (LPWSTR)((ULONG_PTR)pif2 + (pACL->AceCount * sizeof(INHERITED_FROM)));
687         for (i = 0; i < pACL->AceCount; i++)
688         {
689             pif2[i].GenerationGap = pif[i].GenerationGap;
690             if (pif[i].AncestorName != NULL)
691             {
692                 pif2[i].AncestorName = lpBuf;
693                 wcscpy(lpBuf,
694                         pif[i].AncestorName);
695                 lpBuf += wcslen(pif[i].AncestorName) + 1;
696             }
697             else
698                 pif2[i].AncestorName = NULL;
699         }
700 
701         /* return the newly allocated array */
702         *ppInheritArray = pif2;
703     }
704 
705 Cleanup:
706     FreeInheritedFromArray(pif, pACL->AceCount, NULL);
707     HeapFree(GetProcessHeap(), 0, pif);
708 
709     return HRESULT_FROM_WIN32(ErrorCode);
710 }
711 
712 /******************************************************************************
713    Implementation of the CRegKeySecurity constructor
714  ******************************************************************************/
715 
716 static PCRegKeySecurity
717 CRegKeySecurity_fnConstructor(LPWSTR lpRegKey,
718                               HKEY hRootKey,
719                               SI_OBJECT_INFO *ObjectInfo,
720                               BOOL *Btn)
721 {
722     PCRegKeySecurity obj;
723 
724     obj = (PCRegKeySecurity)HeapAlloc(GetProcessHeap(),
725                                       HEAP_ZERO_MEMORY,
726                                       FIELD_OFFSET(CRegKeySecurity,
727                                                    szRegKey[wcslen(lpRegKey) + 1]));
728     if (obj != NULL)
729     {
730         obj->ref = 1;
731         obj->lpISecurityInformationVtbl = &vtblISecurityInformation;
732 #if REGEDIT_IMPLEMENT_ISECURITYINFORMATION2
733         obj->lpISecurityInformation2Vtbl = &vtblISecurityInformation2;
734 #endif
735         obj->lpIEffectivePermissionVtbl = &vtblIEffectivePermission;
736         obj->lpISecurityObjectTypeInfoVtbl =  &vtblISecurityObjectTypeInfo;
737         obj->ObjectInfo = *ObjectInfo;
738         obj->Btn = Btn;
739         obj->hRootKey = hRootKey;
740         StringCbCopyW(obj->szRegKey, sizeof(obj->szRegKey), lpRegKey);
741     }
742     else
743         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
744 
745     return obj;
746 }
747 
748 /******************************************************************************/
749 /******************************************************************************/
750 /******************************************************************************/
751 
752 typedef struct _CHANGE_CONTEXT
753 {
754   HKEY hKey;
755   LPWSTR KeyString;
756 } CHANGE_CONTEXT, *PCHANGE_CONTEXT;
757 
758 typedef BOOL (WINAPI *PEDITSECURITY)(HWND hwndOwner,
759                                      struct ISecurityInformation *psi);
760 
761 static PEDITSECURITY pfnEditSecurity;
762 static HMODULE hAclUiDll;
763 
764 BOOL
765 InitializeAclUiDll(VOID)
766 {
767     if (!(hAclUiDll = LoadLibraryW(L"aclui.dll")))
768     {
769         return FALSE;
770     }
771 
772     if (!(pfnEditSecurity = (PEDITSECURITY)GetProcAddress(hAclUiDll,
773                                                          "EditSecurity")))
774     {
775         FreeLibrary(hAclUiDll);
776         hAclUiDll = NULL;
777         return FALSE;
778     }
779 
780     return TRUE;
781 }
782 
783 VOID
784 UnloadAclUiDll(VOID)
785 {
786     if (hAclUiDll != NULL)
787     {
788         FreeLibrary(hAclUiDll);
789     }
790 }
791 
792 BOOL
793 RegKeyEditPermissions(HWND hWndOwner,
794                       HKEY hKey,
795                       LPCWSTR lpMachine,
796                       LPCWSTR lpKeyName)
797 {
798     BOOL Result = FALSE;
799     LPCWSTR lphKey = NULL;
800     LPWSTR lpKeyPath = NULL;
801     PCRegKeySecurity RegKeySecurity;
802     SI_OBJECT_INFO ObjectInfo;
803     size_t lnMachine = 0, lnKeyName = 0;
804 
805     if (pfnEditSecurity == NULL)
806     {
807         return FALSE;
808     }
809 
810     if (lpMachine != NULL)
811         lnMachine = wcslen(lpMachine);
812     if (lpKeyName != NULL)
813         lnKeyName = wcslen(lpKeyName);
814 
815     /* build registry path */
816     if (lpMachine != NULL &&
817         (lpMachine[0] == L'\0' ||
818          (lpMachine[0] == L'.' && lpMachine[1] == L'.')))
819     {
820         lnMachine = 0;
821     }
822 
823     if (hKey == HKEY_CLASSES_ROOT)
824         lphKey = L"CLASSES_ROOT";
825     else if (hKey == HKEY_CURRENT_USER)
826         lphKey = L"CURRENT_USER";
827     else if (hKey == HKEY_LOCAL_MACHINE)
828         lphKey = L"MACHINE";
829     else if (hKey == HKEY_USERS)
830         lphKey = L"USERS";
831     else if (hKey == HKEY_CURRENT_CONFIG)
832         lphKey = L"CONFIG";
833     else
834     goto Cleanup;
835 
836     lpKeyPath = HeapAlloc(GetProcessHeap(),
837                           0,
838                           (2 + lnMachine + 1 + wcslen(lphKey) + 1 + lnKeyName) * sizeof(WCHAR));
839     if (lpKeyPath == NULL)
840     {
841         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
842         goto Cleanup;
843     }
844     lpKeyPath[0] = L'\0';
845 
846     if (lnMachine != 0)
847     {
848         wcscat(lpKeyPath, L"\\\\");
849         wcscat(lpKeyPath, lpMachine);
850         wcscat(lpKeyPath, L"\\");
851     }
852 
853     wcscat(lpKeyPath, lphKey);
854     if (lpKeyName != NULL && lpKeyName[0] != L'\0')
855     {
856         if (lpKeyName[0] != L'\\')
857             wcscat(lpKeyPath, L"\\");
858 
859         wcscat(lpKeyPath, lpKeyName);
860     }
861 
862     ObjectInfo.dwFlags = SI_EDIT_ALL  | SI_ADVANCED | SI_CONTAINER | SI_EDIT_EFFECTIVE | SI_EDIT_PERMS |
863                              SI_OWNER_RECURSE | SI_RESET_DACL_TREE | SI_RESET_SACL_TREE;
864     ObjectInfo.hInstance = hInst;
865     ObjectInfo.pszServerName = (LPWSTR)lpMachine;
866     ObjectInfo.pszObjectName = (LPWSTR)lpKeyName; /* FIXME */
867     ObjectInfo.pszPageTitle = (LPWSTR)lpKeyName; /* FIXME */
868 
869     if (!(RegKeySecurity = CRegKeySecurity_fnConstructor(lpKeyPath,
870                                                          hKey,
871                                                          &ObjectInfo,
872                                                          &Result)))
873     {
874         goto Cleanup;
875     }
876 
877     /* display the security editor dialog */
878     pfnEditSecurity(hWndOwner, impl_to_interface(RegKeySecurity, ISecurityInformation));
879 
880     /* dereference the interface, it should be destroyed here */
881     CRegKeySecurity_fnRelease(RegKeySecurity);
882 
883 Cleanup:
884     if (lpKeyPath != NULL)
885         HeapFree(GetProcessHeap(), 0, lpKeyPath);
886 
887     return Result;
888 }
889 
890 /* EOF */
891