2 * ReactOS Access Control List Editor
3 * Copyright (C) 2004 ReactOS Team
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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>
31 HINSTANCE hDllInstance
;
34 DestroySecurityPage(IN PSECURITY_PAGE sp
)
36 if(sp
->hiUsrs
!= NULL
)
38 ImageList_Destroy(sp
->hiUsrs
);
41 HeapFree(GetProcessHeap(),
47 FreeAceList(IN PACE_LISTITEM
*AceListHead
)
49 PACE_LISTITEM CurItem
, NextItem
;
51 CurItem
= *AceListHead
;
52 while (CurItem
!= NULL
)
54 /* free the SID string if present */
55 if (CurItem
->DisplayString
!= NULL
)
57 LocalFree((HLOCAL
)CurItem
->DisplayString
);
60 /* free the ACE list item */
61 NextItem
= CurItem
->Next
;
62 HeapFree(GetProcessHeap(),
72 FindSidInAceList(IN PACE_LISTITEM AceListHead
,
75 PACE_LISTITEM CurItem
;
77 for (CurItem
= AceListHead
;
79 CurItem
= CurItem
->Next
)
81 if (EqualSid((PSID
)(CurItem
+ 1),
92 ReloadUsersGroupsList(IN PSECURITY_PAGE sp
)
94 PSECURITY_DESCRIPTOR SecurityDescriptor
;
95 BOOL DaclPresent
, DaclDefaulted
;
99 /* delete the cached ACL */
100 FreeAceList(&sp
->AceListHead
);
103 hRet
= sp
->psi
->lpVtbl
->GetSecurity(sp
->psi
,
104 DACL_SECURITY_INFORMATION
,
107 if (SUCCEEDED(hRet
) && SecurityDescriptor
!= NULL
)
109 if (GetSecurityDescriptorDacl(SecurityDescriptor
,
114 PACE_LISTITEM AceListItem
, *NextAcePtr
;
118 DWORD AccountNameSize
, DomainNameSize
, SidLength
;
119 SID_NAME_USE SidNameUse
;
122 NextAcePtr
= &sp
->AceListHead
;
125 AceIndex
< Dacl
->AceCount
;
132 Sid
= (PSID
)&((PACCESS_ALLOWED_ACE
)Ace
)->SidStart
;
134 if (!FindSidInAceList(sp
->AceListHead
,
137 SidLength
= GetLengthSid(Sid
);
142 /* calculate the size of the buffer we need to calculate */
143 LookupAccountSid(sp
->ServerName
,
151 /* allocate the ace */
152 AceListItem
= HeapAlloc(GetProcessHeap(),
154 sizeof(ACE_LISTITEM
) +
156 ((AccountNameSize
+ DomainNameSize
) * sizeof(WCHAR
)));
157 if (AceListItem
!= NULL
)
159 AceListItem
->AccountName
= (LPWSTR
)((ULONG_PTR
)(AceListItem
+ 1) + SidLength
);
160 AceListItem
->DomainName
= AceListItem
->AccountName
+ AccountNameSize
;
163 (PSID
)(AceListItem
+ 1),
166 LookupResult
= ERROR_SUCCESS
;
167 if (!LookupAccountSid(sp
->ServerName
,
169 AceListItem
->AccountName
,
171 AceListItem
->DomainName
,
175 LookupResult
= GetLastError();
176 if (LookupResult
!= ERROR_NONE_MAPPED
)
178 HeapFree(GetProcessHeap(),
185 if (AccountNameSize
== 0)
187 AceListItem
->AccountName
= NULL
;
189 if (DomainNameSize
== 0)
191 AceListItem
->DomainName
= NULL
;
194 AceListItem
->Next
= NULL
;
195 if (LookupResult
== ERROR_NONE_MAPPED
)
197 if (!ConvertSidToStringSid(Sid
,
198 &AceListItem
->DisplayString
))
200 AceListItem
->DisplayString
= NULL
;
205 LSA_HANDLE LsaHandle
;
208 AceListItem
->DisplayString
= NULL
;
210 /* read the domain of the SID */
211 if (OpenLSAPolicyHandle(sp
->ServerName
,
212 POLICY_LOOKUP_NAMES
| POLICY_VIEW_LOCAL_INFORMATION
,
215 PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain
;
216 PLSA_TRANSLATED_NAME Names
;
217 PLSA_TRUST_INFORMATION Domain
;
218 PLSA_UNICODE_STRING DomainName
;
219 PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo
= NULL
;
221 Status
= LsaLookupSids(LsaHandle
,
226 if (NT_SUCCESS(Status
))
228 if (ReferencedDomain
!= NULL
&&
229 Names
->DomainIndex
>= 0)
231 Domain
= &ReferencedDomain
->Domains
[Names
->DomainIndex
];
232 DomainName
= &Domain
->Name
;
240 AceListItem
->SidNameUse
= Names
->Use
;
247 /* query the domain name for BUILTIN accounts */
248 Status
= LsaQueryInformationPolicy(LsaHandle
,
249 PolicyAccountDomainInformation
,
250 (PVOID
*)&PolicyAccountDomainInfo
);
251 if (NT_SUCCESS(Status
))
253 DomainName
= &PolicyAccountDomainInfo
->DomainName
;
255 /* make the user believe this is a group */
256 AceListItem
->SidNameUse
= SidTypeGroup
;
265 AceListItem
->DisplayString
= (LPWSTR
)LocalAlloc(LMEM_FIXED
,
266 (AccountNameSize
* sizeof(WCHAR
)) +
267 (DomainName
->Length
+ sizeof(WCHAR
)) +
268 (Names
->Name
.Length
+ sizeof(WCHAR
)) +
269 (4 * sizeof(WCHAR
)));
270 if (AceListItem
->DisplayString
!= NULL
)
274 /* NOTE: LSA_UNICODE_STRINGs are not always NULL-terminated! */
276 wcscpy(AceListItem
->DisplayString
,
277 AceListItem
->AccountName
);
278 wcscat(AceListItem
->DisplayString
,
280 s
= AceListItem
->DisplayString
+ wcslen(AceListItem
->DisplayString
);
284 s
+= DomainName
->Length
/ sizeof(WCHAR
);
289 s
+= Names
->Name
.Length
/ sizeof(WCHAR
);
294 /* mark the ace as a user unless it's a
296 if (PolicyAccountDomainInfo
== NULL
)
298 AceListItem
->SidNameUse
= SidTypeUser
;
304 case SidTypeWellKnownGroup
:
306 /* make the user believe this is a group */
307 AceListItem
->SidNameUse
= SidTypeGroup
;
313 DPRINT("Unhandled SID type: 0x%x\n", Names
->Use
);
318 if (PolicyAccountDomainInfo
!= NULL
)
320 LsaFreeMemory(PolicyAccountDomainInfo
);
323 LsaFreeMemory(ReferencedDomain
);
324 LsaFreeMemory(Names
);
330 /* append item to the cached ACL */
331 *NextAcePtr
= AceListItem
;
332 NextAcePtr
= &AceListItem
->Next
;
337 LocalFree((HLOCAL
)SecurityDescriptor
);
342 AddAceListEntry(IN PSECURITY_PAGE sp
,
343 IN PACE_LISTITEM AceListItem
,
349 li
.mask
= LVIF_IMAGE
| LVIF_PARAM
| LVIF_STATE
| LVIF_TEXT
;
352 li
.state
= (Selected
? LVIS_SELECTED
: 0);
353 li
.stateMask
= LVIS_SELECTED
;
354 li
.pszText
= (AceListItem
->DisplayString
!= NULL
? AceListItem
->DisplayString
: AceListItem
->AccountName
);
355 switch (AceListItem
->SidNameUse
)
367 li
.lParam
= (LPARAM
)AceListItem
;
369 return ListView_InsertItem(sp
->hWndAceList
,
374 FillUsersGroupsList(IN PSECURITY_PAGE sp
)
377 PACE_LISTITEM CurItem
;
380 SelLParam
= ListViewGetSelectedItemData(sp
->hWndAceList
);
382 DisableRedrawWindow(sp
->hWndAceList
);
384 ListView_DeleteAllItems(sp
->hWndAceList
);
386 ReloadUsersGroupsList(sp
);
388 for (CurItem
= sp
->AceListHead
;
390 CurItem
= CurItem
->Next
)
395 (SelLParam
== (LPARAM
)CurItem
));
398 EnableRedrawWindow(sp
->hWndAceList
);
400 GetClientRect(sp
->hWndAceList
, &rcLvClient
);
402 ListView_SetColumnWidth(sp
->hWndAceList
,
408 UpdateControlStates(IN PSECURITY_PAGE sp
)
410 PACE_LISTITEM Selected
= (PACE_LISTITEM
)ListViewGetSelectedItemData(sp
->hWndAceList
);
412 EnableWindow(sp
->hBtnRemove
, Selected
!= NULL
);
413 EnableWindow(sp
->hAceCheckList
, Selected
!= NULL
);
415 if (Selected
!= NULL
)
419 if (LoadAndFormatString(hDllInstance
,
422 Selected
->AccountName
))
424 SetWindowText(sp
->hPermissionsForLabel
,
427 LocalFree((HLOCAL
)szLabel
);
430 /* FIXME - update the checkboxes */
434 WCHAR szPermissions
[255];
436 if (LoadString(hDllInstance
,
439 sizeof(szPermissions
) / sizeof(szPermissions
[0])))
441 SetWindowText(sp
->hPermissionsForLabel
,
445 SendMessage(sp
->hAceCheckList
,
453 SecurityPageCallback(IN HWND hwnd
,
455 IN LPPROPSHEETPAGE ppsp
)
457 PSECURITY_PAGE sp
= (PSECURITY_PAGE
)ppsp
->lParam
;
467 DestroySecurityPage(sp
);
468 UnregisterCheckListControl();
477 SetAceCheckListColumns(IN HWND hAceCheckList
,
484 GetWindowRect(hLabel
,
487 pt
.x
= (rcLabel
.right
- rcLabel
.left
) / 2;
488 MapWindowPoints(hLabel
,
493 SendMessage(hAceCheckList
,
494 CLM_SETCHECKBOXCOLUMN
,
500 LoadPermissionsList(IN PSECURITY_PAGE sp
,
501 IN GUID
*GuidObjectType
,
503 OUT SI_ACCESS
*DefaultAccess
)
506 PSI_ACCESS AccessList
;
507 ULONG nAccessList
, DefaultAccessIndex
;
509 /* clear the permissions list */
511 SendMessage(sp
->hAceCheckList
,
516 /* query the access rights from the server */
517 hRet
= sp
->psi
->lpVtbl
->GetAccessRights(sp
->psi
,
522 &DefaultAccessIndex
);
523 if (SUCCEEDED(hRet
) && nAccessList
!= 0)
526 PSI_ACCESS CurAccess
, LastAccess
;
527 WCHAR NameBuffer
[MAX_PATH
];
529 /* save the default access rights to be used when adding ACEs later */
530 if (DefaultAccess
!= NULL
)
532 *DefaultAccess
= AccessList
[DefaultAccessIndex
];
535 LastAccess
= AccessList
+ nAccessList
;
536 for (CurAccess
= &AccessList
[0];
537 CurAccess
!= LastAccess
;
540 if (CurAccess
->dwFlags
& dwFlags
)
542 /* get the permission name, load it from a string table if necessary */
543 if (IS_INTRESOURCE(CurAccess
->pszName
))
545 if (!LoadString(sp
->ObjectInfo
.hInstance
,
546 (UINT
)((ULONG_PTR
)CurAccess
->pszName
),
548 sizeof(NameBuffer
) / sizeof(NameBuffer
[0])))
550 LoadString(hDllInstance
,
553 sizeof(NameBuffer
) / sizeof(NameBuffer
[0]));
555 NameStr
= NameBuffer
;
559 NameStr
= CurAccess
->pszName
;
562 SendMessage(sp
->hAceCheckList
,
571 static INT_PTR CALLBACK
572 SecurityPageProc(IN HWND hwndDlg
,
583 NMHDR
*pnmh
= (NMHDR
*)lParam
;
584 sp
= (PSECURITY_PAGE
)GetWindowLongPtr(hwndDlg
,
588 if (pnmh
->hwndFrom
== sp
->hWndAceList
)
592 case LVN_ITEMCHANGED
:
594 LPNMLISTVIEW pnmv
= (LPNMLISTVIEW
)lParam
;
596 if ((pnmv
->uChanged
& LVIF_STATE
) &&
597 ((pnmv
->uOldState
& (LVIS_FOCUSED
| LVIS_SELECTED
)) ||
598 (pnmv
->uNewState
& (LVIS_FOCUSED
| LVIS_SELECTED
))))
600 UpdateControlStates(sp
);
606 else if (pnmh
->hwndFrom
== sp
->hAceCheckList
)
610 case CLN_CHANGINGITEMCHECKBOX
:
612 PNMCHANGEITEMCHECKBOX pcicb
= (PNMCHANGEITEMCHECKBOX
)lParam
;
614 /* make sure only one of both checkboxes is only checked
618 pcicb
->NewState
&= ~((pcicb
->CheckBox
!= CLB_DENY
) ? CIS_DENY
: CIS_ALLOW
);
630 sp
= (PSECURITY_PAGE
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
637 sp
->hWndAceList
= GetDlgItem(hwndDlg
, IDC_ACELIST
);
638 sp
->hBtnRemove
= GetDlgItem(hwndDlg
, IDC_ACELIST_REMOVE
);
639 sp
->hBtnAdvanced
= GetDlgItem(hwndDlg
, IDC_ADVANCED
);
640 sp
->hAceCheckList
= GetDlgItem(hwndDlg
, IDC_ACE_CHECKLIST
);
641 sp
->hPermissionsForLabel
= GetDlgItem(hwndDlg
, IDC_LABEL_PERMISSIONS_FOR
);
643 sp
->SpecialPermCheckIndex
= -1;
645 if ((sp
->ObjectInfo
.dwFlags
& SI_SERVER_IS_DC
) &&
646 sp
->ObjectInfo
.pszServerName
!= NULL
&&
647 sp
->ObjectInfo
.pszServerName
[0] != L
'\0')
649 sp
->ServerName
= sp
->ObjectInfo
.pszServerName
;
652 /* save the pointer to the structure */
653 SetWindowLongPtr(hwndDlg
,
657 sp
->hiUsrs
= ImageList_LoadBitmap(hDllInstance
,
658 MAKEINTRESOURCE(IDB_USRGRPIMAGES
),
663 /* setup the listview control */
664 ListView_SetExtendedListViewStyleEx(sp
->hWndAceList
,
665 LVS_EX_FULLROWSELECT
,
666 LVS_EX_FULLROWSELECT
);
667 ListView_SetImageList(sp
->hWndAceList
,
671 GetClientRect(sp
->hWndAceList
, &rcLvClient
);
673 /* add a column to the list view */
674 lvc
.mask
= LVCF_FMT
| LVCF_WIDTH
;
675 lvc
.fmt
= LVCFMT_LEFT
;
676 lvc
.cx
= rcLvClient
.right
;
677 ListView_InsertColumn(sp
->hWndAceList
, 0, &lvc
);
679 FillUsersGroupsList(sp
);
681 ListViewSelectItem(sp
->hWndAceList
,
684 /* calculate the columns of the allow/deny checkboxes */
685 SetAceCheckListColumns(sp
->hAceCheckList
,
687 GetDlgItem(hwndDlg
, IDC_LABEL_ALLOW
));
688 SetAceCheckListColumns(sp
->hAceCheckList
,
690 GetDlgItem(hwndDlg
, IDC_LABEL_DENY
));
692 LoadPermissionsList(sp
,
695 ((sp
->ObjectInfo
.dwFlags
& SI_CONTAINER
) ? SI_ACCESS_CONTAINER
: 0),
698 /* hide controls in case the flags aren't present */
699 if (sp
->ObjectInfo
.dwFlags
& SI_ADVANCED
)
701 WCHAR szSpecialPermissions
[255];
703 /* editing the permissions is least the user can do when
704 the advanced button is showed */
705 sp
->ObjectInfo
.dwFlags
|= SI_EDIT_PERMS
;
707 if (LoadString(hDllInstance
,
708 IDS_SPECIAL_PERMISSIONS
,
709 szSpecialPermissions
,
710 sizeof(szSpecialPermissions
) / sizeof(szSpecialPermissions
[0])))
712 /* add the special permissions check item */
713 sp
->SpecialPermCheckIndex
= (INT
)SendMessage(sp
->hAceCheckList
,
715 CIS_ALLOWDISABLED
| CIS_DENYDISABLED
| CIS_NONE
,
716 (LPARAM
)szSpecialPermissions
);
721 ShowWindow(sp
->hBtnAdvanced
,
723 ShowWindow(GetDlgItem(hwndDlg
, IDC_LABEL_ADVANCED
),
727 /* enable quicksearch for the permissions checklist control */
728 SendMessage(sp
->hAceCheckList
,
729 CLM_ENABLEQUICKSEARCH
,
741 * CreateSecurityPage EXPORTED
747 CreateSecurityPage(IN LPSECURITYINFO psi
)
750 PSECURITY_PAGE sPage
;
751 SI_OBJECT_INFO ObjectInfo
;
756 SetLastError(ERROR_INVALID_PARAMETER
);
758 DPRINT("No ISecurityInformation class passed!\n");
762 /* get the object information from the server. Zero the structure before
763 because some applications seem to return SUCCESS but only seem to set the
764 fields they care about. */
765 ZeroMemory(&ObjectInfo
, sizeof(ObjectInfo
));
766 hRet
= psi
->lpVtbl
->GetObjectInformation(psi
, &ObjectInfo
);
772 DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n");
776 if (!RegisterCheckListControl(hDllInstance
))
778 DPRINT("Registering the CHECKLIST_ACLUI class failed!\n");
782 sPage
= HeapAlloc(GetProcessHeap(),
784 sizeof(SECURITY_PAGE
));
787 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
789 DPRINT("Not enough memory to allocate a SECURITY_PAGE!\n");
793 sPage
->ObjectInfo
= ObjectInfo
;
795 ZeroMemory(&psp
, sizeof(psp
));
797 psp
.dwSize
= sizeof(PROPSHEETPAGE
);
798 psp
.dwFlags
= PSP_USECALLBACK
;
799 psp
.hInstance
= hDllInstance
;
800 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SECPAGE
);
801 psp
.pfnDlgProc
= SecurityPageProc
;
802 psp
.lParam
= (LPARAM
)sPage
;
803 psp
.pfnCallback
= SecurityPageCallback
;
805 if(ObjectInfo
.dwFlags
& SI_PAGE_TITLE
)
807 psp
.pszTitle
= ObjectInfo
.pszPageTitle
;
809 if (psp
.pszTitle
!= NULL
)
811 psp
.dwFlags
|= PSP_USETITLE
;
819 /* NOTE: the SECURITY_PAGE structure will be freed by the property page
822 return CreatePropertySheetPage(&psp
);
827 * EditSecurity EXPORTED
833 EditSecurity(IN HWND hwndOwner
,
834 IN LPSECURITYINFO psi
)
837 SI_OBJECT_INFO ObjectInfo
;
839 HPROPSHEETPAGE hPages
[1];
845 SetLastError(ERROR_INVALID_PARAMETER
);
847 DPRINT("No ISecurityInformation class passed!\n");
851 /* get the object information from the server. Zero the structure before
852 because some applications seem to return SUCCESS but only seem to set the
853 fields they care about. */
854 ZeroMemory(&ObjectInfo
, sizeof(ObjectInfo
));
855 hRet
= psi
->lpVtbl
->GetObjectInformation(psi
, &ObjectInfo
);
861 DPRINT("GetObjectInformation() failed!\n");
865 /* create the page */
866 hPages
[0] = CreateSecurityPage(psi
);
867 if(hPages
[0] == NULL
)
869 DPRINT("CreateSecurityPage(), couldn't create property sheet!\n");
873 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
874 psh
.dwFlags
= PSH_DEFAULT
;
875 psh
.hwndParent
= hwndOwner
;
876 psh
.hInstance
= hDllInstance
;
878 /* Set the page title to the object name, make sure the format string
879 has "%1" NOT "%s" because it uses FormatMessage() to automatically
880 allocate the right amount of memory. */
881 LoadAndFormatString(hDllInstance
,
884 ObjectInfo
.pszObjectName
);
885 psh
.pszCaption
= lpCaption
;
887 psh
.nPages
= sizeof(hPages
) / sizeof(HPROPSHEETPAGE
);
891 Ret
= (PropertySheet(&psh
) != -1);
893 if(lpCaption
!= NULL
)
895 LocalFree((HLOCAL
)lpCaption
);
902 DllMain(IN HINSTANCE hinstDLL
,
904 IN LPVOID lpvReserved
)
908 case DLL_PROCESS_ATTACH
:
909 hDllInstance
= hinstDLL
;
911 case DLL_THREAD_ATTACH
:
912 case DLL_THREAD_DETACH
:
913 case DLL_PROCESS_DETACH
: