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