xref: /reactos/dll/win32/aclui/aclui.c (revision 4561998a)
1 /*
2  * ReactOS Access Control List Editor
3  * Copyright (C) 2004-2005 ReactOS Team
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 /*
20  * PROJECT:         ReactOS Access Control List Editor
21  * FILE:            lib/aclui/aclui.c
22  * PURPOSE:         Access Control List Editor
23  * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
24  *
25  * UPDATE HISTORY:
26  *      08/10/2004  Created
27  */
28 
29 #include "precomp.h"
30 
31 #include <sddl.h>
32 
33 #define NDEBUG
34 #include <debug.h>
35 
36 #include "resource.h"
37 
38 HINSTANCE hDllInstance;
39 
40 #define SIDN_LOOKUPSUCCEEDED    (0x101)
41 typedef struct _SIDLOOKUPNOTIFYINFO
42 {
43     NMHDR nmh;
44     PSID Sid;
45     PSIDREQRESULT SidRequestResult;
46 } SIDLOOKUPNOTIFYINFO, *PSIDLOOKUPNOTIFYINFO;
47 
48 static PSID
49 AceHeaderToSID(IN PACE_HEADER AceHeader)
50 {
51     PSID Sid = NULL;
52     switch (AceHeader->AceType)
53     {
54         case ACCESS_ALLOWED_ACE_TYPE:
55             Sid = (PSID)&((PACCESS_ALLOWED_ACE)AceHeader)->SidStart;
56             break;
57 #if 0
58         case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
59             Sid = (PSID)&((PACCESS_ALLOWED_CALLBACK_ACE)AceHeader)->SidStart;
60             break;
61         case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
62             Sid = (PSID)&((PACCESS_ALLOWED_CALLBACK_OBJECT_ACE)AceHeader)->SidStart;
63             break;
64 #endif
65         case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
66             Sid = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)AceHeader)->SidStart;
67             break;
68         case ACCESS_DENIED_ACE_TYPE:
69             Sid = (PSID)&((PACCESS_DENIED_ACE)AceHeader)->SidStart;
70             break;
71 #if 0
72         case ACCESS_DENIED_CALLBACK_ACE_TYPE:
73             Sid = (PSID)&((PACCESS_DENIED_CALLBACK_ACE)AceHeader)->SidStart;
74             break;
75         case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
76             Sid = (PSID)&((PACCESS_DENIED_CALLBACK_OBJECT_ACE)AceHeader)->SidStart;
77             break;
78 #endif
79         case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
80             Sid = (PSID)&((PACCESS_DENIED_OBJECT_ACE)AceHeader)->SidStart;
81             break;
82     }
83 
84     return Sid;
85 }
86 
87 static VOID
88 DestroySecurityPage(IN PSECURITY_PAGE sp)
89 {
90     if(sp->hiPrincipals != NULL)
91     {
92         ImageList_Destroy(sp->hiPrincipals);
93     }
94 
95     DestroySidCacheMgr(sp->SidCacheMgr);
96 
97     if (sp->OwnerSid != NULL)
98         LocalFree((HLOCAL)sp->OwnerSid);
99 
100     HeapFree(GetProcessHeap(),
101              0,
102              sp);
103 
104     CoUninitialize();
105 }
106 
107 static VOID
108 FreePrincipalsList(IN PSECURITY_PAGE sp,
109                    IN PPRINCIPAL_LISTITEM *PrincipalsListHead)
110 {
111     PPRINCIPAL_LISTITEM CurItem, NextItem;
112     PACE_ENTRY AceEntry, NextAceEntry;
113 
114     CurItem = *PrincipalsListHead;
115     while (CurItem != NULL)
116     {
117         /* Free all ACEs */
118         AceEntry = CurItem->ACEs;
119         while (AceEntry != NULL)
120         {
121             NextAceEntry = AceEntry->Next;
122             HeapFree(GetProcessHeap(),
123                      0,
124                      AceEntry);
125             AceEntry = NextAceEntry;
126         }
127 
128         /* free the SID string if present */
129         if (CurItem->SidReqResult != NULL)
130         {
131             DereferenceSidReqResult(sp->SidCacheMgr,
132                                     CurItem->SidReqResult);
133         }
134 
135         if (CurItem->DisplayString != NULL)
136         {
137             LocalFree((HLOCAL)CurItem->DisplayString);
138         }
139 
140         /* free the ACE list item */
141         NextItem = CurItem->Next;
142         HeapFree(GetProcessHeap(),
143                  0,
144                  CurItem);
145         CurItem = NextItem;
146     }
147 
148     *PrincipalsListHead = NULL;
149 }
150 
151 static PACE_ENTRY
152 AddAceToPrincipal(IN PPRINCIPAL_LISTITEM Principal,
153                   IN PACE_HEADER AceHeader)
154 {
155     PACE_ENTRY AceEntry, *AceLink;
156 
157     AceEntry = HeapAlloc(GetProcessHeap(),
158                          0,
159                          sizeof(ACE_ENTRY) + AceHeader->AceSize);
160     if (AceEntry != NULL)
161     {
162         AceEntry->Next = NULL;
163 
164         /* copy the ACE */
165         CopyMemory(AceEntry + 1,
166                    AceHeader,
167                    AceHeader->AceSize);
168 
169         /* append it to the list */
170         AceLink = &Principal->ACEs;
171         while (*AceLink != NULL)
172         {
173             AceLink = &(*AceLink)->Next;
174         }
175         *AceLink = AceEntry;
176     }
177 
178     return AceEntry;
179 }
180 
181 static PPRINCIPAL_LISTITEM
182 FindSidInPrincipalsListAddAce(IN PPRINCIPAL_LISTITEM PrincipalsListHead,
183                               IN PSID Sid,
184                               IN PACE_HEADER AceHeader)
185 {
186     PPRINCIPAL_LISTITEM CurItem;
187 
188     for (CurItem = PrincipalsListHead;
189          CurItem != NULL;
190          CurItem = CurItem->Next)
191     {
192         if (EqualSid((PSID)(CurItem + 1),
193                      Sid))
194         {
195             if (AddAceToPrincipal(CurItem,
196                                   AceHeader) != NULL)
197             {
198                 return CurItem;
199             }
200 
201             /* unable to add the ACE to the principal */
202             break;
203         }
204     }
205 
206     return NULL;
207 }
208 
209 static VOID
210 SidLookupCompletion(IN HANDLE SidCacheMgr,
211                     IN PSID Sid,
212                     IN PSIDREQRESULT SidRequestResult,
213                     IN PVOID Context)
214 {
215     PSECURITY_PAGE sp = (PSECURITY_PAGE)Context;
216 
217     /* NOTE: this routine may be executed in a different thread
218              than the GUI! */
219 
220     if (SidRequestResult != NULL)
221     {
222         SIDLOOKUPNOTIFYINFO LookupInfo;
223 
224         LookupInfo.nmh.hwndFrom = sp->hWnd;
225         LookupInfo.nmh.idFrom = 0;
226         LookupInfo.nmh.code = SIDN_LOOKUPSUCCEEDED;
227         LookupInfo.Sid = Sid;
228         LookupInfo.SidRequestResult = SidRequestResult;
229 
230         /* notify the page that the sid lookup succeeded */
231         SendMessage(sp->hWnd,
232                     WM_NOTIFY,
233                     (WPARAM)LookupInfo.nmh.idFrom,
234                     (LPARAM)&LookupInfo.nmh);
235     }
236 }
237 
238 static PPRINCIPAL_LISTITEM
239 AddPrincipalToList(IN PSECURITY_PAGE sp,
240                    IN PSID Sid,
241                    IN PACE_HEADER AceHeader,
242                    OUT BOOL *LookupDeferred  OPTIONAL)
243 {
244     PPRINCIPAL_LISTITEM PrincipalListItem = NULL, *PrincipalLink;
245     PACE_ENTRY AceEntry;
246     BOOL Deferred = FALSE;
247 
248     if (!FindSidInPrincipalsListAddAce(sp->PrincipalsListHead,
249                                        Sid,
250                                        AceHeader))
251     {
252         DWORD SidLength;
253 
254         PrincipalLink = &sp->PrincipalsListHead;
255         while (*PrincipalLink != NULL)
256         {
257             PrincipalLink = &(*PrincipalLink)->Next;
258         }
259 
260         SidLength = GetLengthSid(Sid);
261 
262         /* allocate the principal */
263         PrincipalListItem = HeapAlloc(GetProcessHeap(),
264                                       0,
265                                       sizeof(PRINCIPAL_LISTITEM) + SidLength);
266         if (PrincipalListItem != NULL)
267         {
268             PrincipalListItem->DisplayString = NULL;
269             PrincipalListItem->SidReqResult = NULL;
270 
271             CopySid(SidLength,
272                     (PSID)(PrincipalListItem + 1),
273                     Sid);
274 
275             /* allocate some memory for the ACE and copy it */
276             AceEntry = HeapAlloc(GetProcessHeap(),
277                                  0,
278                                  sizeof(ACE_ENTRY) + AceHeader->AceSize);
279             if (AceEntry != NULL)
280             {
281                 AceEntry->Next = NULL;
282                 CopyMemory(AceEntry + 1,
283                            AceHeader,
284                            AceHeader->AceSize);
285 
286                 /* add the ACE to the list */
287                 PrincipalListItem->ACEs = AceEntry;
288 
289                 PrincipalListItem->Next = NULL;
290 
291                 /* append item to the principals list */
292                 *PrincipalLink = PrincipalListItem;
293 
294                 /* lookup the SID now */
295                 Deferred = !LookupSidCache(sp->SidCacheMgr,
296                                            Sid,
297                                            SidLookupCompletion,
298                                            sp);
299             }
300             else
301             {
302                 HeapFree(GetProcessHeap(),
303                          0,
304                          PrincipalListItem);
305                 PrincipalListItem = NULL;
306             }
307         }
308     }
309 
310     if (PrincipalListItem != NULL && LookupDeferred != NULL)
311     {
312         *LookupDeferred = Deferred;
313     }
314 
315     return PrincipalListItem;
316 }
317 
318 static LPWSTR
319 GetDisplayStringFromSidRequestResult(IN PSIDREQRESULT SidReqResult)
320 {
321     LPWSTR lpDisplayString = NULL;
322 
323     if (SidReqResult->SidNameUse == SidTypeUser ||
324         SidReqResult->SidNameUse == SidTypeGroup)
325     {
326         LoadAndFormatString(hDllInstance,
327                             IDS_USERDOMAINFORMAT,
328                             &lpDisplayString,
329                             SidReqResult->AccountName,
330                             SidReqResult->DomainName,
331                             SidReqResult->AccountName);
332     }
333     else
334     {
335         LoadAndFormatString(hDllInstance,
336                             IDS_USERFORMAT,
337                             &lpDisplayString,
338                             SidReqResult->AccountName);
339     }
340 
341     return lpDisplayString;
342 }
343 
344 static LPWSTR
345 GetPrincipalDisplayString(IN PPRINCIPAL_LISTITEM PrincipalListItem)
346 {
347     LPWSTR lpDisplayString = NULL;
348 
349     if (PrincipalListItem->SidReqResult != NULL)
350     {
351         lpDisplayString = GetDisplayStringFromSidRequestResult(PrincipalListItem->SidReqResult);
352     }
353     else
354     {
355         ConvertSidToStringSidW((PSID)(PrincipalListItem + 1),
356                                &lpDisplayString);
357     }
358 
359     return lpDisplayString;
360 }
361 
362 static LPWSTR
363 GetPrincipalAccountNameString(IN PPRINCIPAL_LISTITEM PrincipalListItem)
364 {
365     LPWSTR lpDisplayString = NULL;
366 
367     if (PrincipalListItem->SidReqResult != NULL)
368     {
369         LoadAndFormatString(hDllInstance,
370                             IDS_USERFORMAT,
371                             &lpDisplayString,
372                             PrincipalListItem->SidReqResult->AccountName);
373     }
374     else
375     {
376         ConvertSidToStringSid((PSID)(PrincipalListItem + 1),
377                               &lpDisplayString);
378     }
379 
380     return lpDisplayString;
381 }
382 
383 static VOID
384 CreatePrincipalListItem(OUT LVITEM *li,
385                         IN PSECURITY_PAGE sp,
386                         IN PPRINCIPAL_LISTITEM PrincipalListItem,
387                         IN INT Index,
388                         IN BOOL Selected)
389 {
390     INT ImageIndex = 2;
391 
392     if (PrincipalListItem->SidReqResult != NULL)
393     {
394         switch (PrincipalListItem->SidReqResult->SidNameUse)
395         {
396             case SidTypeUser:
397                 ImageIndex = 0;
398                 break;
399             case SidTypeWellKnownGroup:
400             case SidTypeGroup:
401                 ImageIndex = 1;
402                 break;
403             default:
404                 break;
405         }
406     }
407 
408     li->mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
409     li->iItem = Index;
410     li->iSubItem = 0;
411     li->state = (Selected ? LVIS_SELECTED : 0);
412     li->stateMask = LVIS_SELECTED;
413     li->pszText = PrincipalListItem->DisplayString;
414     li->iImage = ImageIndex;
415     li->lParam = (LPARAM)PrincipalListItem;
416 }
417 
418 static INT
419 AddPrincipalListEntry(IN PSECURITY_PAGE sp,
420                       IN PPRINCIPAL_LISTITEM PrincipalListItem,
421                       IN INT Index,
422                       IN BOOL Selected)
423 {
424     LVITEM li;
425     INT Ret;
426 
427     if (PrincipalListItem->DisplayString != NULL)
428     {
429         LocalFree((HLOCAL)PrincipalListItem->DisplayString);
430     }
431     PrincipalListItem->DisplayString = GetPrincipalDisplayString(PrincipalListItem);
432 
433     CreatePrincipalListItem(&li,
434                             sp,
435                             PrincipalListItem,
436                             Index,
437                             Selected);
438 
439     Ret = ListView_InsertItem(sp->hWndPrincipalsList,
440                               &li);
441 
442     return Ret;
443 }
444 
445 static int CALLBACK
446 PrincipalCompare(IN LPARAM lParam1,
447                  IN LPARAM lParam2,
448                  IN LPARAM lParamSort)
449 {
450     PPRINCIPAL_LISTITEM Item1 = (PPRINCIPAL_LISTITEM)lParam1;
451     PPRINCIPAL_LISTITEM Item2 = (PPRINCIPAL_LISTITEM)lParam2;
452 
453     if (Item1->DisplayString != NULL && Item2->DisplayString != NULL)
454     {
455         return wcscmp(Item1->DisplayString,
456                       Item2->DisplayString);
457     }
458 
459     return 0;
460 }
461 
462 static VOID
463 UpdatePrincipalListItem(IN PSECURITY_PAGE sp,
464                         IN INT PrincipalIndex,
465                         IN PPRINCIPAL_LISTITEM PrincipalListItem,
466                         IN PSIDREQRESULT SidReqResult)
467 {
468     LVITEM li;
469 
470     /* replace the request result structure */
471     if (PrincipalListItem->SidReqResult != NULL)
472     {
473         DereferenceSidReqResult(sp->SidCacheMgr,
474                                 PrincipalListItem->SidReqResult);
475     }
476 
477     ReferenceSidReqResult(sp->SidCacheMgr,
478                           SidReqResult);
479     PrincipalListItem->SidReqResult = SidReqResult;
480 
481     /* update the display string */
482     if (PrincipalListItem->DisplayString != NULL)
483     {
484         LocalFree((HLOCAL)PrincipalListItem->DisplayString);
485     }
486     PrincipalListItem->DisplayString = GetPrincipalDisplayString(PrincipalListItem);
487 
488     /* update the list item */
489     CreatePrincipalListItem(&li,
490                             sp,
491                             PrincipalListItem,
492                             PrincipalIndex,
493                             FALSE);
494 
495     /* don't change the list item state */
496     li.mask &= ~(LVIF_STATE | LVIF_PARAM);
497 
498     (void)ListView_SetItem(sp->hWndPrincipalsList,
499                            &li);
500 
501     /* sort the principals list view again */
502     (void)ListView_SortItems(sp->hWndPrincipalsList,
503                              PrincipalCompare,
504                              (LPARAM)sp);
505 }
506 
507 static VOID
508 ReloadPrincipalsList(IN PSECURITY_PAGE sp)
509 {
510     PSECURITY_DESCRIPTOR SecurityDescriptor;
511     BOOL DaclPresent, DaclDefaulted, OwnerDefaulted;
512     PACL Dacl = NULL;
513     PSID OwnerSid = NULL;
514     LPTSTR OwnerSidString;
515     DWORD SidLen;
516     HRESULT hRet;
517 
518     /* delete the cached ACL */
519     FreePrincipalsList(sp,
520                        &sp->PrincipalsListHead);
521 
522     /* query the ACL */
523     hRet = sp->psi->lpVtbl->GetSecurity(sp->psi,
524                                         DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
525                                         &SecurityDescriptor,
526                                         FALSE);
527     if (SUCCEEDED(hRet) && SecurityDescriptor != NULL)
528     {
529         if (GetSecurityDescriptorOwner(SecurityDescriptor,
530                                        &OwnerSid,
531                                        &OwnerDefaulted))
532         {
533             sp->OwnerDefaulted = OwnerDefaulted;
534             if (sp->OwnerSid != NULL)
535             {
536                 LocalFree((HLOCAL)sp->OwnerSid);
537                 sp->OwnerSid = NULL;
538             }
539 
540             SidLen = GetLengthSid(OwnerSid);
541             if (SidLen == 0)
542                 goto ClearOwner;
543 
544             sp->OwnerSid = (PSID)LocalAlloc(LMEM_FIXED,
545                                             SidLen);
546             if (sp->OwnerSid != NULL)
547             {
548                 if (CopySid(SidLen,
549                             sp->OwnerSid,
550                             OwnerSid))
551                 {
552                     /* Lookup the SID now */
553                     if (!LookupSidCache(sp->SidCacheMgr,
554                                         sp->OwnerSid,
555                                         SidLookupCompletion,
556                                         sp))
557                     {
558                         /* Lookup was deferred */
559                         if (ConvertSidToStringSid(sp->OwnerSid,
560                                                   &OwnerSidString))
561                         {
562                             SetDlgItemText(sp->hWnd,
563                                            IDC_OWNER,
564                                            OwnerSidString);
565                             LocalFree((HLOCAL)OwnerSidString);
566                         }
567                         else
568                             goto ClearOwner;
569                     }
570                 }
571                 else
572                     goto ClearOwner;
573             }
574             else
575                 goto ClearOwner;
576         }
577         else
578         {
579 ClearOwner:
580             SetDlgItemText(sp->hWnd,
581                            IDC_OWNER,
582                            NULL);
583         }
584 
585         if (GetSecurityDescriptorDacl(SecurityDescriptor,
586                                       &DaclPresent,
587                                       &Dacl,
588                                       &DaclDefaulted) &&
589             DaclPresent && Dacl != NULL)
590         {
591             PSID Sid;
592             PACE_HEADER AceHeader;
593             ULONG AceIndex;
594 
595             for (AceIndex = 0;
596                  AceIndex < Dacl->AceCount;
597                  AceIndex++)
598             {
599                 if (GetAce(Dacl,
600                            AceIndex,
601                            (LPVOID*)&AceHeader) &&
602                     AceHeader != NULL)
603                 {
604                     BOOL LookupDeferred;
605                     PPRINCIPAL_LISTITEM PrincipalListItem;
606 
607                     Sid = AceHeaderToSID(AceHeader);
608 
609                     PrincipalListItem = AddPrincipalToList(sp,
610                                                            Sid,
611                                                            AceHeader,
612                                                            &LookupDeferred);
613 
614                     if (PrincipalListItem != NULL && LookupDeferred)
615                     {
616                         AddPrincipalListEntry(sp,
617                                               PrincipalListItem,
618                                               -1,
619                                               FALSE);
620                     }
621                 }
622             }
623         }
624         LocalFree((HLOCAL)SecurityDescriptor);
625     }
626 }
627 
628 static VOID
629 UpdateControlStates(IN PSECURITY_PAGE sp)
630 {
631     PPRINCIPAL_LISTITEM Selected = (PPRINCIPAL_LISTITEM)ListViewGetSelectedItemData(sp->hWndPrincipalsList);
632 
633     EnableWindow(sp->hBtnRemove,
634                  Selected != NULL);
635     EnableWindow(sp->hAceCheckList,
636                  Selected != NULL);
637 
638     if (Selected != NULL)
639     {
640         LPWSTR szLabel;
641         LPWSTR szDisplayString;
642 
643         szDisplayString = GetPrincipalAccountNameString(Selected);
644         if (LoadAndFormatString(hDllInstance,
645                                 IDS_PERMISSIONS_FOR,
646                                 &szLabel,
647                                 szDisplayString))
648         {
649             SetWindowText(sp->hPermissionsForLabel,
650                           szLabel);
651 
652             LocalFree((HLOCAL)szLabel);
653         }
654 
655         LocalFree((HLOCAL)szDisplayString);
656 
657         /* FIXME - update the checkboxes */
658     }
659     else
660     {
661         WCHAR szPermissions[255];
662 
663         if (LoadString(hDllInstance,
664                        IDS_PERMISSIONS,
665                        szPermissions,
666                        sizeof(szPermissions) / sizeof(szPermissions[0])))
667         {
668             SetWindowText(sp->hPermissionsForLabel,
669                           szPermissions);
670         }
671 
672         SendMessage(sp->hAceCheckList,
673                     CLM_CLEARCHECKBOXES,
674                     0,
675                     0);
676     }
677 }
678 
679 static void
680 UpdatePrincipalInfo(IN PSECURITY_PAGE sp,
681                     IN PSIDLOOKUPNOTIFYINFO LookupInfo)
682 {
683     PPRINCIPAL_LISTITEM CurItem;
684     LPWSTR DisplayName;
685 
686     if (sp->OwnerSid != NULL &&
687         EqualSid(sp->OwnerSid,
688                  LookupInfo->Sid))
689     {
690         if (LookupInfo->SidRequestResult != NULL)
691             DisplayName = GetDisplayStringFromSidRequestResult(LookupInfo->SidRequestResult);
692         else if (!ConvertSidToStringSidW(LookupInfo->Sid,
693                                          &DisplayName))
694         {
695             DisplayName = NULL;
696         }
697 
698         if (DisplayName != NULL)
699         {
700             SetDlgItemTextW(sp->hWnd,
701                             IDC_OWNER,
702                             DisplayName);
703 
704             LocalFree((HLOCAL)DisplayName);
705         }
706     }
707 
708     for (CurItem = sp->PrincipalsListHead;
709          CurItem != NULL;
710          CurItem = CurItem->Next)
711     {
712         if (EqualSid((PSID)(CurItem + 1),
713                      LookupInfo->Sid))
714         {
715             INT PrincipalIndex;
716             LVFINDINFO lvfi;
717 
718             /* find the principal in the list */
719             lvfi.flags = LVFI_PARAM;
720             lvfi.lParam = (LPARAM)CurItem;
721             PrincipalIndex = ListView_FindItem(sp->hWndPrincipalsList,
722                                                -1,
723                                                &lvfi);
724 
725             if (PrincipalIndex != -1)
726             {
727                 /* update the principal in the list view control */
728                 UpdatePrincipalListItem(sp,
729                                         PrincipalIndex,
730                                         CurItem,
731                                         LookupInfo->SidRequestResult);
732 
733                 if (ListViewGetSelectedItemData(sp->hWndPrincipalsList) == (LPARAM)CurItem)
734                 {
735                     UpdateControlStates(sp);
736                 }
737             }
738             else
739             {
740                 AddPrincipalListEntry(sp,
741                                       CurItem,
742                                       -1,
743                                       FALSE);
744             }
745             break;
746         }
747     }
748 }
749 
750 static UINT CALLBACK
751 SecurityPageCallback(IN HWND hwnd,
752                      IN UINT uMsg,
753                      IN LPPROPSHEETPAGE ppsp)
754 {
755     PSECURITY_PAGE sp = (PSECURITY_PAGE)ppsp->lParam;
756 
757     switch (uMsg)
758     {
759         case PSPCB_CREATE:
760         {
761             return TRUE;
762         }
763         case PSPCB_RELEASE:
764         {
765             DestroySecurityPage(sp);
766             return FALSE;
767         }
768     }
769 
770     return FALSE;
771 }
772 
773 static VOID
774 SetAceCheckListColumns(IN HWND hAceCheckList,
775                        IN UINT Button,
776                        IN HWND hLabel)
777 {
778     POINT pt;
779     RECT rcLabel;
780 
781     GetWindowRect(hLabel,
782                   &rcLabel);
783     pt.y = 0;
784     pt.x = (rcLabel.right - rcLabel.left) / 2;
785     MapWindowPoints(hLabel,
786                     hAceCheckList,
787                     &pt,
788                     1);
789 
790     SendMessage(hAceCheckList,
791                 CLM_SETCHECKBOXCOLUMN,
792                 Button,
793                 pt.x);
794 }
795 
796 static VOID
797 LoadPermissionsList(IN PSECURITY_PAGE sp,
798                     IN GUID *GuidObjectType,
799                     IN DWORD dwFlags,
800                     OUT SI_ACCESS *DefaultAccess)
801 {
802     HRESULT hRet;
803     PSI_ACCESS AccessList;
804     ULONG nAccessList, DefaultAccessIndex;
805     WCHAR szSpecialPermissions[255];
806     BOOLEAN SpecialPermissionsPresent = FALSE;
807     ACCESS_MASK SpecialPermissionsMask = 0;
808 
809     /* clear the permissions list */
810 
811     SendMessage(sp->hAceCheckList,
812                 CLM_CLEAR,
813                 0,
814                 0);
815 
816     /* query the access rights from the server */
817     hRet = sp->psi->lpVtbl->GetAccessRights(sp->psi,
818                                             GuidObjectType,
819                                             dwFlags, /* FIXME */
820                                             &AccessList,
821                                             &nAccessList,
822                                             &DefaultAccessIndex);
823     if (SUCCEEDED(hRet) && nAccessList != 0)
824     {
825         LPCWSTR NameStr;
826         PSI_ACCESS CurAccess, LastAccess;
827         WCHAR NameBuffer[MAX_PATH];
828 
829         /* save the default access rights to be used when adding ACEs later */
830         if (DefaultAccess != NULL)
831         {
832             *DefaultAccess = AccessList[DefaultAccessIndex];
833         }
834 
835         LastAccess = AccessList + nAccessList;
836         for (CurAccess = &AccessList[0];
837              CurAccess != LastAccess;
838              CurAccess++)
839         {
840             if (CurAccess->dwFlags & dwFlags)
841             {
842                 /* get the permission name, load it from a string table if necessary */
843                 if (IS_INTRESOURCE(CurAccess->pszName))
844                 {
845                     if (!LoadString(sp->ObjectInfo.hInstance,
846                                     (UINT)((ULONG_PTR)CurAccess->pszName),
847                                     NameBuffer,
848                                     sizeof(NameBuffer) / sizeof(NameBuffer[0])))
849                     {
850                         LoadString(hDllInstance,
851                                    IDS_UNKNOWN,
852                                    NameBuffer,
853                                    sizeof(NameBuffer) / sizeof(NameBuffer[0]));
854                     }
855                     NameStr = NameBuffer;
856                 }
857                 else
858                 {
859                     NameStr = CurAccess->pszName;
860                 }
861 
862                 SendMessage(sp->hAceCheckList,
863                             CLM_ADDITEM,
864                             (WPARAM)CurAccess->mask,
865                             (LPARAM)NameStr);
866             }
867             else if (CurAccess->dwFlags & SI_ACCESS_SPECIFIC)
868             {
869                 SpecialPermissionsPresent = TRUE;
870                 SpecialPermissionsMask |= CurAccess->mask;
871             }
872         }
873     }
874 
875     /* add the special permissions check item in case the specific access rights
876        aren't displayed */
877     if (SpecialPermissionsPresent &&
878         LoadString(hDllInstance,
879                    IDS_SPECIAL_PERMISSIONS,
880                    szSpecialPermissions,
881                    sizeof(szSpecialPermissions) / sizeof(szSpecialPermissions[0])))
882     {
883         /* add the special permissions check item */
884         sp->SpecialPermCheckIndex = (INT)SendMessage(sp->hAceCheckList,
885                                                      CLM_ADDITEM,
886                                                      (WPARAM)SpecialPermissionsMask,
887                                                      (LPARAM)szSpecialPermissions);
888         if (sp->SpecialPermCheckIndex != -1)
889         {
890             SendMessage(sp->hAceCheckList,
891                         CLM_SETITEMSTATE,
892                         (WPARAM)sp->SpecialPermCheckIndex,
893                         CIS_ALLOWDISABLED | CIS_DENYDISABLED | CIS_NONE);
894         }
895     }
896 }
897 
898 static VOID
899 ResizeControls(IN PSECURITY_PAGE sp,
900                IN INT Width,
901                IN INT Height)
902 {
903     HWND hWndAllow, hWndDeny, hWndOwnerEdit;
904     RECT rcControl, rcControl2, rcControl3, rcWnd;
905     INT cxWidth, cxEdge, btnSpacing;
906     POINT pt, pt2;
907     HDWP dwp;
908     INT nControls = 8;
909     LVCOLUMN lvc;
910 
911     hWndAllow = GetDlgItem(sp->hWnd,
912                            IDC_LABEL_ALLOW);
913     hWndDeny = GetDlgItem(sp->hWnd,
914                           IDC_LABEL_DENY);
915 
916     GetWindowRect(sp->hWnd,
917                   &rcWnd);
918 
919     cxEdge = GetSystemMetrics(SM_CXEDGE);
920 
921     /* use the left margin of the principal list view control for all control
922        margins */
923     pt.x = 0;
924     pt.y = 0;
925     MapWindowPoints(sp->hWndPrincipalsList,
926                     sp->hWnd,
927                     &pt,
928                     1);
929     cxWidth = Width - (2 * pt.x);
930 
931     if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
932     {
933         nControls += 2;
934     }
935 
936     if ((dwp = BeginDeferWindowPos(nControls)))
937     {
938         /* resize the owner edit field */
939         hWndOwnerEdit = GetDlgItem(sp->hWnd,
940                                    IDC_OWNER);
941         GetWindowRect(hWndOwnerEdit,
942                       &rcControl);
943         pt2.x = 0;
944         pt2.y = 0;
945         MapWindowPoints(hWndOwnerEdit,
946                         sp->hWnd,
947                         &pt2,
948                         1);
949         if (!(dwp = DeferWindowPos(dwp,
950                                    hWndOwnerEdit,
951                                    NULL,
952                                    0,
953                                    0,
954                                    Width - pt.x - pt2.x,
955                                    rcControl.bottom - rcControl.top,
956                                    SWP_NOMOVE | SWP_NOZORDER)))
957         {
958             goto EndDeferWnds;
959         }
960 
961         /* resize the Principal list view */
962         GetWindowRect(sp->hWndPrincipalsList,
963                       &rcControl);
964         if (!(dwp = DeferWindowPos(dwp,
965                                    sp->hWndPrincipalsList,
966                                    NULL,
967                                    0,
968                                    0,
969                                    cxWidth,
970                                    rcControl.bottom - rcControl.top,
971                                    SWP_NOMOVE | SWP_NOZORDER)))
972         {
973             goto EndDeferWnds;
974         }
975 
976         /* move the Add Principal button */
977         GetWindowRect(sp->hBtnAdd,
978                       &rcControl);
979         GetWindowRect(sp->hBtnRemove,
980                       &rcControl2);
981         btnSpacing = rcControl2.left - rcControl.right;
982         pt2.x = 0;
983         pt2.y = 0;
984         MapWindowPoints(sp->hBtnAdd,
985                         sp->hWnd,
986                         &pt2,
987                         1);
988         if (!(dwp = DeferWindowPos(dwp,
989                                    sp->hBtnAdd,
990                                    NULL,
991                                    pt.x + cxWidth - (rcControl2.right - rcControl2.left) -
992                                        (rcControl.right - rcControl.left) -
993                                        btnSpacing - cxEdge,
994                                    pt2.y,
995                                    0,
996                                    0,
997                                    SWP_NOSIZE | SWP_NOZORDER)))
998         {
999             goto EndDeferWnds;
1000         }
1001 
1002         /* move the Delete Principal button */
1003         pt2.x = 0;
1004         pt2.y = 0;
1005         MapWindowPoints(sp->hBtnRemove,
1006                         sp->hWnd,
1007                         &pt2,
1008                         1);
1009         if (!(dwp = DeferWindowPos(dwp,
1010                                    sp->hBtnRemove,
1011                                    NULL,
1012                                    pt.x + cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
1013                                    pt2.y,
1014                                    0,
1015                                    0,
1016                                    SWP_NOSIZE | SWP_NOZORDER)))
1017         {
1018             goto EndDeferWnds;
1019         }
1020 
1021         /* move the Permissions For label */
1022         GetWindowRect(hWndAllow,
1023                       &rcControl);
1024         GetWindowRect(hWndDeny,
1025                       &rcControl2);
1026         GetWindowRect(sp->hPermissionsForLabel,
1027                       &rcControl3);
1028         pt2.x = 0;
1029         pt2.y = 0;
1030         MapWindowPoints(sp->hPermissionsForLabel,
1031                         sp->hWnd,
1032                         &pt2,
1033                         1);
1034         if (!(dwp = DeferWindowPos(dwp,
1035                                    sp->hPermissionsForLabel,
1036                                    NULL,
1037                                    0,
1038                                    0,
1039                                    cxWidth - (rcControl2.right - rcControl2.left) -
1040                                        (rcControl.right - rcControl.left) -
1041                                        (2 * btnSpacing) - cxEdge,
1042                                    rcControl3.bottom - rcControl3.top,
1043                                    SWP_NOMOVE | SWP_NOZORDER)))
1044         {
1045             goto EndDeferWnds;
1046         }
1047 
1048         /* move the Allow label */
1049         pt2.x = 0;
1050         pt2.y = 0;
1051         MapWindowPoints(hWndAllow,
1052                         sp->hWnd,
1053                         &pt2,
1054                         1);
1055         if (!(dwp = DeferWindowPos(dwp,
1056                                    hWndAllow,
1057                                    NULL,
1058                                    cxWidth - (rcControl2.right - rcControl2.left) -
1059                                        (rcControl.right - rcControl.left) -
1060                                        btnSpacing - cxEdge,
1061                                    pt2.y,
1062                                    0,
1063                                    0,
1064                                    SWP_NOSIZE | SWP_NOZORDER)))
1065         {
1066             goto EndDeferWnds;
1067         }
1068 
1069         /* move the Deny label */
1070         pt2.x = 0;
1071         pt2.y = 0;
1072         MapWindowPoints(hWndDeny,
1073                         sp->hWnd,
1074                         &pt2,
1075                         1);
1076         if (!(dwp = DeferWindowPos(dwp,
1077                                    hWndDeny,
1078                                    NULL,
1079                                    cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
1080                                    pt2.y,
1081                                    0,
1082                                    0,
1083                                    SWP_NOSIZE | SWP_NOZORDER)))
1084         {
1085             goto EndDeferWnds;
1086         }
1087 
1088         /* resize the Permissions check list box */
1089         GetWindowRect(sp->hAceCheckList,
1090                       &rcControl);
1091         GetWindowRect(sp->hBtnAdvanced,
1092                       &rcControl2);
1093         GetWindowRect(GetDlgItem(sp->hWnd,
1094                                  IDC_LABEL_ADVANCED),
1095                       &rcControl3);
1096         if (!(dwp = DeferWindowPos(dwp,
1097                                    sp->hAceCheckList,
1098                                    NULL,
1099                                    0,
1100                                    0,
1101                                    cxWidth,
1102                                    ((sp->ObjectInfo.dwFlags & SI_ADVANCED) ?
1103                                        Height - (rcControl.top - rcWnd.top) -
1104                                            (rcControl3.bottom - rcControl3.top) - pt.x - btnSpacing :
1105                                        Height - (rcControl.top - rcWnd.top) - pt.x),
1106                                    SWP_NOMOVE | SWP_NOZORDER)))
1107         {
1108             goto EndDeferWnds;
1109         }
1110 
1111         if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
1112         {
1113             /* move and resize the Advanced label */
1114             if (!(dwp = DeferWindowPos(dwp,
1115                                        GetDlgItem(sp->hWnd,
1116                                                   IDC_LABEL_ADVANCED),
1117                                        NULL,
1118                                        pt.x,
1119                                        Height - (rcControl3.bottom - rcControl3.top) - pt.x,
1120                                        cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
1121                                        rcControl3.bottom - rcControl3.top,
1122                                        SWP_NOZORDER)))
1123             {
1124                 goto EndDeferWnds;
1125             }
1126 
1127             /* move and resize the Advanced button */
1128             if (!(dwp = DeferWindowPos(dwp,
1129                                        sp->hBtnAdvanced,
1130                                        NULL,
1131                                        cxWidth - (rcControl2.right - rcControl2.left) + pt.x,
1132                                        Height - (rcControl2.bottom - rcControl2.top) - pt.x,
1133                                        0,
1134                                        0,
1135                                        SWP_NOSIZE | SWP_NOZORDER)))
1136             {
1137                 goto EndDeferWnds;
1138             }
1139         }
1140 
1141         EndDeferWindowPos(dwp);
1142     }
1143 
1144 EndDeferWnds:
1145     /* update the width of the principal list view column */
1146     GetClientRect(sp->hWndPrincipalsList,
1147                   &rcControl);
1148     lvc.mask = LVCF_WIDTH;
1149     lvc.cx = rcControl.right;
1150     (void)ListView_SetColumn(sp->hWndPrincipalsList,
1151                              0,
1152                              &lvc);
1153 
1154     /* calculate the columns of the allow/deny checkboxes */
1155     SetAceCheckListColumns(sp->hAceCheckList,
1156                            CLB_ALLOW,
1157                            hWndAllow);
1158     SetAceCheckListColumns(sp->hAceCheckList,
1159                            CLB_DENY,
1160                            hWndDeny);
1161 }
1162 
1163 static PACE_HEADER
1164 BuildDefaultPrincipalAce(IN PSECURITY_PAGE sp,
1165                          IN PSID pSid)
1166 {
1167     PACCESS_ALLOWED_ACE Ace;
1168     DWORD SidLen;
1169     WORD AceSize;
1170 
1171     SidLen = GetLengthSid(pSid);
1172     AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE,
1173                            SidStart) + (WORD)SidLen;
1174     Ace = HeapAlloc(GetProcessHeap(),
1175                     0,
1176                     AceSize);
1177     if (Ace != NULL)
1178     {
1179         Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
1180         Ace->Header.AceFlags = 0; /* FIXME */
1181         Ace->Header.AceSize = AceSize;
1182         Ace->Mask = sp->DefaultAccess.mask;
1183 
1184         if (CopySid(SidLen,
1185                     (PSID)&Ace->SidStart,
1186                     pSid))
1187         {
1188             return &Ace->Header;
1189         }
1190 
1191         HeapFree(GetProcessHeap(),
1192                  0,
1193                  Ace);
1194     }
1195 
1196     return NULL;
1197 }
1198 
1199 static BOOL
1200 AddSelectedPrincipal(IN IDsObjectPicker *pDsObjectPicker,
1201                      IN HWND hwndParent  OPTIONAL,
1202                      IN PSID pSid,
1203                      IN PVOID Context  OPTIONAL)
1204 {
1205     PACE_HEADER AceHeader;
1206     PSECURITY_PAGE sp = (PSECURITY_PAGE)Context;
1207 
1208     AceHeader = BuildDefaultPrincipalAce(sp,
1209                                          pSid);
1210     if (AceHeader != NULL)
1211     {
1212         PPRINCIPAL_LISTITEM PrincipalListItem;
1213         BOOL LookupDeferred;
1214 
1215         PrincipalListItem = AddPrincipalToList(sp,
1216                                                pSid,
1217                                                AceHeader,
1218                                                &LookupDeferred);
1219 
1220         if (PrincipalListItem != NULL && LookupDeferred)
1221         {
1222             AddPrincipalListEntry(sp,
1223                                   PrincipalListItem,
1224                                   -1,
1225                                   FALSE);
1226         }
1227 
1228         HeapFree(GetProcessHeap(),
1229                  0,
1230                  AceHeader);
1231     }
1232 
1233     return TRUE;
1234 }
1235 
1236 static INT_PTR CALLBACK
1237 SecurityPageProc(IN HWND hwndDlg,
1238                  IN UINT uMsg,
1239                  IN WPARAM wParam,
1240                  IN LPARAM lParam)
1241 {
1242     PSECURITY_PAGE sp;
1243     INT_PTR Ret = FALSE;
1244 
1245     sp = (PSECURITY_PAGE)GetWindowLongPtr(hwndDlg, DWLP_USER);
1246     if (sp != NULL || uMsg == WM_INITDIALOG)
1247     {
1248         switch (uMsg)
1249         {
1250             case WM_NOTIFY:
1251             {
1252                 NMHDR *pnmh = (NMHDR*)lParam;
1253 
1254                 if (pnmh->hwndFrom == sp->hWndPrincipalsList)
1255                 {
1256                     switch (pnmh->code)
1257                     {
1258                         case LVN_ITEMCHANGED:
1259                         {
1260                             LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
1261 
1262                             if ((pnmv->uChanged & LVIF_STATE) &&
1263                                 ((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) ||
1264                                  (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))))
1265                             {
1266                                 UpdateControlStates(sp);
1267                             }
1268                             break;
1269                         }
1270                     }
1271                 }
1272                 else if (pnmh->hwndFrom == sp->hAceCheckList)
1273                 {
1274                     switch (pnmh->code)
1275                     {
1276                         case CLN_CHANGINGITEMCHECKBOX:
1277                         {
1278                             PNMCHANGEITEMCHECKBOX pcicb = (PNMCHANGEITEMCHECKBOX)lParam;
1279 
1280                             /* make sure only one of both checkboxes is only checked
1281                                at the same time */
1282                             if (pcicb->Checked)
1283                             {
1284                                 pcicb->NewState &= ~((pcicb->CheckBox != CLB_DENY) ? CIS_DENY : CIS_ALLOW);
1285                             }
1286                             break;
1287                         }
1288                     }
1289                 }
1290                 else if (pnmh->hwndFrom == sp->hWnd)
1291                 {
1292                     switch(pnmh->code)
1293                     {
1294                         case SIDN_LOOKUPSUCCEEDED:
1295                         {
1296                             PSIDLOOKUPNOTIFYINFO LookupInfo = CONTAINING_RECORD(lParam,
1297                                                                                 SIDLOOKUPNOTIFYINFO,
1298                                                                                 nmh);
1299 
1300                             /* a SID lookup succeeded, update the information */
1301                             UpdatePrincipalInfo(sp,
1302                                                 LookupInfo);
1303                             break;
1304                         }
1305                     }
1306                 }
1307                 break;
1308             }
1309 
1310             case WM_COMMAND:
1311             {
1312                 switch (LOWORD(wParam))
1313                 {
1314                     case IDC_ADD_PRINCIPAL:
1315                     {
1316                         HRESULT hRet;
1317 
1318                         hRet = InitializeObjectPicker(sp->ServerName,
1319                                                       &sp->ObjectInfo,
1320                                                       &sp->pDsObjectPicker);
1321                         if (SUCCEEDED(hRet))
1322                         {
1323                             hRet = InvokeObjectPickerDialog(sp->pDsObjectPicker,
1324                                                             hwndDlg,
1325                                                             AddSelectedPrincipal,
1326                                                             sp);
1327                             if (FAILED(hRet))
1328                             {
1329                                 MessageBox(hwndDlg, L"InvokeObjectPickerDialog failed!\n", NULL, 0);
1330                             }
1331 
1332                             /* delete the instance */
1333                             FreeObjectPicker(sp->pDsObjectPicker);
1334                         }
1335                         else
1336                         {
1337                             MessageBox(hwndDlg, L"InitializeObjectPicker failed!\n", NULL, 0);
1338                         }
1339                         break;
1340                     }
1341 
1342                     case IDC_REMOVE_PRINCIPAL:
1343                     {
1344                         PPRINCIPAL_LISTITEM SelectedPrincipal;
1345 
1346                         SelectedPrincipal = (PPRINCIPAL_LISTITEM)ListViewGetSelectedItemData(sp->hWndPrincipalsList);
1347                         if (SelectedPrincipal != NULL)
1348                         {
1349                             /* FIXME */
1350                         }
1351                         break;
1352                     }
1353                 }
1354                 break;
1355             }
1356 
1357             case WM_SIZE:
1358             {
1359                 ResizeControls(sp,
1360                                (INT)LOWORD(lParam),
1361                                (INT)HIWORD(lParam));
1362                 break;
1363             }
1364 
1365             case WM_INITDIALOG:
1366             {
1367                 sp = (PSECURITY_PAGE)((LPPROPSHEETPAGE)lParam)->lParam;
1368                 if(sp != NULL)
1369                 {
1370                     LV_COLUMN lvc;
1371                     RECT rcLvClient;
1372 
1373                     sp->hWnd = hwndDlg;
1374                     sp->hWndPrincipalsList = GetDlgItem(hwndDlg, IDC_PRINCIPALS);
1375                     sp->hBtnAdd = GetDlgItem(hwndDlg, IDC_ADD_PRINCIPAL);
1376                     sp->hBtnRemove = GetDlgItem(hwndDlg, IDC_REMOVE_PRINCIPAL);
1377                     sp->hBtnAdvanced = GetDlgItem(hwndDlg, IDC_ADVANCED);
1378                     sp->hAceCheckList = GetDlgItem(hwndDlg, IDC_ACE_CHECKLIST);
1379                     sp->hPermissionsForLabel = GetDlgItem(hwndDlg, IDC_LABEL_PERMISSIONS_FOR);
1380 
1381                     sp->SpecialPermCheckIndex = -1;
1382 
1383                     /* save the pointer to the structure */
1384                     SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)sp);
1385 
1386                     (void)ListView_SetExtendedListViewStyleEx(sp->hWndPrincipalsList,
1387                                                               LVS_EX_FULLROWSELECT,
1388                                                               LVS_EX_FULLROWSELECT);
1389 
1390                     sp->hiPrincipals = ImageList_Create(16,
1391                                                         16,
1392                                                         ILC_COLOR32 | ILC_MASK,
1393                                                         0,
1394                                                         3);
1395                     if (sp->hiPrincipals != NULL)
1396                     {
1397                         HBITMAP hbmImages;
1398 
1399                         hbmImages = LoadBitmap(hDllInstance,
1400                                                MAKEINTRESOURCE(IDB_USRGRPIMAGES));
1401                         if (hbmImages != NULL)
1402                         {
1403                             ImageList_AddMasked(sp->hiPrincipals,
1404                                                 hbmImages,
1405                                                 RGB(255,
1406                                                     0,
1407                                                     255));
1408 
1409                             DeleteObject(hbmImages);
1410                         }
1411                     }
1412 
1413                     /* setup the listview control */
1414                     if (sp->hiPrincipals != NULL)
1415                     {
1416                         (void)ListView_SetImageList(sp->hWndPrincipalsList,
1417                                                     sp->hiPrincipals,
1418                                                     LVSIL_SMALL);
1419                     }
1420 
1421                     GetClientRect(sp->hWndPrincipalsList,
1422                                   &rcLvClient);
1423 
1424                     /* add a column to the list view */
1425                     lvc.mask = LVCF_FMT | LVCF_WIDTH;
1426                     lvc.fmt = LVCFMT_LEFT;
1427                     lvc.cx = rcLvClient.right;
1428                     (void)ListView_InsertColumn(sp->hWndPrincipalsList,
1429                                                 0,
1430                                                 &lvc);
1431 
1432                     ReloadPrincipalsList(sp);
1433 
1434                     ListViewSelectItem(sp->hWndPrincipalsList,
1435                                        0);
1436 
1437                     /* calculate the columns of the allow/deny checkboxes */
1438                     SetAceCheckListColumns(sp->hAceCheckList,
1439                                            CLB_ALLOW,
1440                                            GetDlgItem(hwndDlg, IDC_LABEL_ALLOW));
1441                     SetAceCheckListColumns(sp->hAceCheckList,
1442                                            CLB_DENY,
1443                                            GetDlgItem(hwndDlg, IDC_LABEL_DENY));
1444 
1445                     LoadPermissionsList(sp,
1446                                         NULL,
1447                                         SI_ACCESS_GENERAL |
1448                                         ((sp->ObjectInfo.dwFlags & SI_CONTAINER) ? SI_ACCESS_CONTAINER : 0),
1449                                         &sp->DefaultAccess);
1450 
1451                     /* hide controls in case the flags aren't present */
1452                     if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
1453                     {
1454                         /* editing the permissions is least the user can do when
1455                            the advanced button is showed */
1456                         sp->ObjectInfo.dwFlags |= SI_EDIT_PERMS;
1457                     }
1458                     else
1459                     {
1460                         ShowWindow(sp->hBtnAdvanced,
1461                                    SW_HIDE);
1462                         ShowWindow(GetDlgItem(hwndDlg, IDC_LABEL_ADVANCED),
1463                                    SW_HIDE);
1464                     }
1465 
1466                     /* enable quicksearch for the permissions checklist control */
1467                     SendMessage(sp->hAceCheckList,
1468                                 CLM_ENABLEQUICKSEARCH,
1469                                 TRUE,
1470                                 0);
1471 
1472                     UpdateControlStates(sp);
1473                 }
1474 
1475                 Ret = TRUE;
1476                 break;
1477             }
1478         }
1479     }
1480     return Ret;
1481 }
1482 
1483 
1484 /*
1485  * CreateSecurityPage							EXPORTED
1486  *
1487  * @implemented
1488  */
1489 HPROPSHEETPAGE
1490 WINAPI
1491 CreateSecurityPage(IN LPSECURITYINFO psi)
1492 {
1493     PROPSHEETPAGE psp = {0};
1494     PSECURITY_PAGE sPage;
1495     SI_OBJECT_INFO ObjectInfo = {0};
1496     HANDLE SidCacheMgr;
1497     LPCWSTR SystemName = NULL;
1498     HRESULT hRet;
1499 
1500     if (psi == NULL)
1501     {
1502         SetLastError(ERROR_INVALID_PARAMETER);
1503 
1504         DPRINT("No ISecurityInformation class passed!\n");
1505         return NULL;
1506     }
1507 
1508     /* get the object information from the server. Zero the structure before
1509        because some applications seem to return SUCCESS but only seem to set the
1510        fields they care about. */
1511     hRet = psi->lpVtbl->GetObjectInformation(psi,
1512                                              &ObjectInfo);
1513 
1514     if (FAILED(hRet))
1515     {
1516         SetLastError(hRet);
1517 
1518         DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n");
1519         return NULL;
1520     }
1521 
1522     if ((ObjectInfo.dwFlags & SI_SERVER_IS_DC) &&
1523          ObjectInfo.pszServerName != NULL &&
1524          ObjectInfo.pszServerName[0] != L'\0')
1525     {
1526         SystemName = ObjectInfo.pszServerName;
1527     }
1528 
1529     SidCacheMgr = CreateSidCacheMgr(GetProcessHeap(),
1530                                     SystemName);
1531     if (SidCacheMgr == NULL)
1532     {
1533         DPRINT("Creating the SID cache failed!\n");
1534         return NULL;
1535     }
1536 
1537     hRet = CoInitialize(NULL);
1538     if (FAILED(hRet))
1539     {
1540         DestroySidCacheMgr(SidCacheMgr);
1541         DPRINT("CoInitialize failed!\n");
1542         return NULL;
1543     }
1544 
1545     sPage = HeapAlloc(GetProcessHeap(),
1546                       HEAP_ZERO_MEMORY,
1547                       sizeof(SECURITY_PAGE));
1548     if (sPage == NULL)
1549     {
1550         DestroySidCacheMgr(SidCacheMgr);
1551         CoUninitialize();
1552 
1553         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1554 
1555         DPRINT("Not enough memory to allocate a SECURITY_PAGE!\n");
1556         return NULL;
1557     }
1558 
1559     ZeroMemory(sPage,
1560                sizeof(*sPage));
1561 
1562     sPage->psi = psi;
1563     sPage->ObjectInfo = ObjectInfo;
1564     sPage->ServerName = SystemName;
1565     sPage->SidCacheMgr = SidCacheMgr;
1566 
1567     psp.dwSize = sizeof(PROPSHEETPAGE);
1568     psp.dwFlags = PSP_USECALLBACK;
1569     psp.hInstance = hDllInstance;
1570     psp.pszTemplate = MAKEINTRESOURCE(IDD_SECPAGE);
1571     psp.pfnDlgProc = SecurityPageProc;
1572     psp.lParam = (LPARAM)sPage;
1573     psp.pfnCallback = SecurityPageCallback;
1574 
1575     if (ObjectInfo.dwFlags & SI_PAGE_TITLE)
1576     {
1577         psp.pszTitle = ObjectInfo.pszPageTitle;
1578 
1579         if (psp.pszTitle != NULL)
1580         {
1581             psp.dwFlags |= PSP_USETITLE;
1582         }
1583     }
1584     else
1585     {
1586         psp.pszTitle = NULL;
1587     }
1588 
1589     /* NOTE: the SECURITY_PAGE structure will be freed by the property page
1590              callback! */
1591 
1592     return CreatePropertySheetPage(&psp);
1593 }
1594 
1595 
1596 /*
1597  * EditSecurity								EXPORTED
1598  *
1599  * @implemented
1600  */
1601 BOOL
1602 WINAPI
1603 EditSecurity(IN HWND hwndOwner,
1604              IN LPSECURITYINFO psi)
1605 {
1606     HRESULT hRet;
1607     SI_OBJECT_INFO ObjectInfo = {0};
1608     PROPSHEETHEADER psh;
1609     HPROPSHEETPAGE hPages[1];
1610     LPWSTR lpCaption = NULL;
1611     BOOL Ret;
1612 
1613     if (psi == NULL)
1614     {
1615         SetLastError(ERROR_INVALID_PARAMETER);
1616 
1617         DPRINT("No ISecurityInformation class passed!\n");
1618         return FALSE;
1619     }
1620 
1621     /* get the object information from the server. Zero the structure before
1622        because some applications seem to return SUCCESS but only seem to set the
1623        fields they care about. */
1624     hRet = psi->lpVtbl->GetObjectInformation(psi,
1625                                              &ObjectInfo);
1626 
1627     if (FAILED(hRet))
1628     {
1629         SetLastError(hRet);
1630 
1631         DPRINT("GetObjectInformation() failed!\n");
1632         return FALSE;
1633     }
1634 
1635     /* create the page */
1636     hPages[0] = CreateSecurityPage(psi);
1637     if (hPages[0] == NULL)
1638     {
1639         DPRINT("CreateSecurityPage(), couldn't create property sheet!\n");
1640         return FALSE;
1641     }
1642 
1643     psh.dwSize = sizeof(PROPSHEETHEADER);
1644     psh.dwFlags = PSH_DEFAULT;
1645     psh.hwndParent = hwndOwner;
1646     psh.hInstance = hDllInstance;
1647 
1648     /* Set the page title to the object name, make sure the format string
1649        has "%1" NOT "%s" because it uses FormatMessage() to automatically
1650        allocate the right amount of memory. */
1651     if (LoadAndFormatString(hDllInstance,
1652                             IDS_PSP_TITLE,
1653                             &lpCaption,
1654                             ObjectInfo.pszObjectName))
1655     {
1656         psh.pszCaption = lpCaption;
1657     }
1658     else
1659     {
1660         psh.pszCaption = ObjectInfo.pszObjectName;
1661     }
1662 
1663     psh.nPages = sizeof(hPages) / sizeof(HPROPSHEETPAGE);
1664     psh.nStartPage = 0;
1665     psh.phpage = hPages;
1666 
1667     Ret = (PropertySheet(&psh) != -1);
1668 
1669     if (lpCaption != NULL)
1670     {
1671         LocalFree((HLOCAL)lpCaption);
1672     }
1673 
1674     return Ret;
1675 }
1676 
1677 BOOL
1678 WINAPI
1679 DllMain(IN HINSTANCE hinstDLL,
1680         IN DWORD dwReason,
1681         IN LPVOID lpvReserved)
1682 {
1683     switch (dwReason)
1684     {
1685         case DLL_PROCESS_ATTACH:
1686             hDllInstance = hinstDLL;
1687 
1688             DisableThreadLibraryCalls(hinstDLL);
1689 
1690             if (!RegisterCheckListControl(hinstDLL))
1691             {
1692                 DPRINT("Registering the CHECKLIST_ACLUI class failed!\n");
1693                 return FALSE;
1694             }
1695             break;
1696 
1697         case DLL_PROCESS_DETACH:
1698             UnregisterCheckListControl(hinstDLL);
1699             break;
1700     }
1701 
1702     return TRUE;
1703 }
1704 
1705