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