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(NULL
, /* FIXME */
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(NULL
, /* FIXME */
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(NULL
, /* FIXME */
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
;
317 if (PolicyAccountDomainInfo
!= NULL
)
319 LsaFreeMemory(PolicyAccountDomainInfo
);
322 LsaFreeMemory(ReferencedDomain
);
323 LsaFreeMemory(Names
);
329 /* append item to the cached ACL */
330 *NextAcePtr
= AceListItem
;
331 NextAcePtr
= &AceListItem
->Next
;
336 LocalFree((HLOCAL
)SecurityDescriptor
);
341 AddAceListEntry(IN PSECURITY_PAGE sp
,
342 IN PACE_LISTITEM AceListItem
,
348 li
.mask
= LVIF_IMAGE
| LVIF_PARAM
| LVIF_STATE
| LVIF_TEXT
;
351 li
.state
= (Selected
? LVIS_SELECTED
: 0);
352 li
.stateMask
= LVIS_SELECTED
;
353 li
.pszText
= (AceListItem
->DisplayString
!= NULL
? AceListItem
->DisplayString
: AceListItem
->AccountName
);
354 switch (AceListItem
->SidNameUse
)
366 li
.lParam
= (LPARAM
)AceListItem
;
368 return ListView_InsertItem(sp
->hWndAceList
,
373 FillUsersGroupsList(IN PSECURITY_PAGE sp
)
376 PACE_LISTITEM CurItem
;
379 SelLParam
= ListViewGetSelectedItemData(sp
->hWndAceList
);
381 DisableRedrawWindow(sp
->hWndAceList
);
383 ListView_DeleteAllItems(sp
->hWndAceList
);
385 ReloadUsersGroupsList(sp
);
387 for (CurItem
= sp
->AceListHead
;
389 CurItem
= CurItem
->Next
)
394 (SelLParam
== (LPARAM
)CurItem
));
397 EnableRedrawWindow(sp
->hWndAceList
);
399 GetClientRect(sp
->hWndAceList
, &rcLvClient
);
401 ListView_SetColumnWidth(sp
->hWndAceList
,
407 UpdateControlStates(IN PSECURITY_PAGE sp
)
409 BOOL UserOrGroupSelected
;
411 UserOrGroupSelected
= (ListViewGetSelectedItemData(sp
->hWndAceList
) != 0);
413 EnableWindow(sp
->hBtnRemove
, UserOrGroupSelected
);
417 SecurityPageCallback(IN HWND hwnd
,
419 IN LPPROPSHEETPAGE ppsp
)
421 PSECURITY_PAGE sp
= (PSECURITY_PAGE
)ppsp
->lParam
;
431 DestroySecurityPage(sp
);
432 UnregisterCheckListControl();
441 SetAceCheckListColumns(IN HWND hAceCheckList
,
448 GetWindowRect(hLabel
,
451 pt
.x
= (rcLabel
.right
- rcLabel
.left
) / 2;
452 MapWindowPoints(hLabel
,
457 SendMessage(hAceCheckList
,
458 CLM_SETCHECKBOXCOLUMN
,
464 LoadPermissionsList(IN PSECURITY_PAGE sp
,
465 IN GUID
*GuidObjectType
,
467 OUT SI_ACCESS
*DefaultAccess
)
470 PSI_ACCESS AccessList
;
471 ULONG nAccessList
, DefaultAccessIndex
;
473 /* clear the permissions list */
475 SendMessage(sp
->hAceCheckList
,
480 /* query the access rights from the server */
481 hRet
= sp
->psi
->lpVtbl
->GetAccessRights(sp
->psi
,
486 &DefaultAccessIndex
);
487 if (SUCCEEDED(hRet
) && nAccessList
!= 0)
490 PSI_ACCESS CurAccess
, LastAccess
;
491 WCHAR NameBuffer
[MAX_PATH
];
493 /* save the default access rights to be used when adding ACEs later */
494 if (DefaultAccess
!= NULL
)
496 *DefaultAccess
= AccessList
[DefaultAccessIndex
];
499 LastAccess
= AccessList
+ nAccessList
;
500 for (CurAccess
= &AccessList
[0];
501 CurAccess
!= LastAccess
;
504 if (CurAccess
->dwFlags
& dwFlags
)
506 /* get the permission name, load it from a string table if necessary */
507 if (IS_INTRESOURCE(CurAccess
->pszName
))
509 if (!LoadString(sp
->ObjectInfo
.hInstance
,
510 (UINT
)((ULONG_PTR
)CurAccess
->pszName
),
512 sizeof(NameBuffer
) / sizeof(NameBuffer
[0])))
514 LoadString(hDllInstance
,
517 sizeof(NameBuffer
) / sizeof(NameBuffer
[0]));
519 NameStr
= NameBuffer
;
523 NameStr
= CurAccess
->pszName
;
526 SendMessage(sp
->hAceCheckList
,
528 CIS_DISABLED
| CIS_NONE
,
535 static INT_PTR CALLBACK
536 SecurityPageProc(IN HWND hwndDlg
,
547 NMHDR
*pnmh
= (NMHDR
*)lParam
;
548 if (pnmh
->idFrom
== IDC_ACELIST
)
550 sp
= (PSECURITY_PAGE
)GetWindowLongPtr(hwndDlg
,
556 case LVN_ITEMCHANGED
:
558 UpdateControlStates(sp
);
569 sp
= (PSECURITY_PAGE
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
576 sp
->hWndAceList
= GetDlgItem(hwndDlg
, IDC_ACELIST
);
577 sp
->hBtnRemove
= GetDlgItem(hwndDlg
, IDC_ACELIST_REMOVE
);
578 sp
->hAceCheckList
= GetDlgItem(hwndDlg
, IDC_ACE_CHECKLIST
);
580 /* save the pointer to the structure */
581 SetWindowLongPtr(hwndDlg
,
585 sp
->hiUsrs
= ImageList_LoadBitmap(hDllInstance
,
586 MAKEINTRESOURCE(IDB_USRGRPIMAGES
),
591 /* setup the listview control */
592 ListView_SetExtendedListViewStyleEx(sp
->hWndAceList
,
593 LVS_EX_FULLROWSELECT
,
594 LVS_EX_FULLROWSELECT
);
595 ListView_SetImageList(sp
->hWndAceList
,
599 GetClientRect(sp
->hWndAceList
, &rcLvClient
);
601 /* add a column to the list view */
602 lvc
.mask
= LVCF_FMT
| LVCF_WIDTH
;
603 lvc
.fmt
= LVCFMT_LEFT
;
604 lvc
.cx
= rcLvClient
.right
;
605 ListView_InsertColumn(sp
->hWndAceList
, 0, &lvc
);
607 FillUsersGroupsList(sp
);
609 ListViewSelectItem(sp
->hWndAceList
,
612 /* calculate the columns of the allow/deny checkboxes */
613 SetAceCheckListColumns(sp
->hAceCheckList
,
615 GetDlgItem(hwndDlg
, IDC_LABEL_ALLOW
));
616 SetAceCheckListColumns(sp
->hAceCheckList
,
618 GetDlgItem(hwndDlg
, IDC_LABEL_DENY
));
620 /* FIXME - hide controls in case the flags aren't present */
622 LoadPermissionsList(sp
,
625 ((sp
->ObjectInfo
.dwFlags
& SI_CONTAINER
) ? SI_ACCESS_CONTAINER
: 0),
636 * CreateSecurityPage EXPORTED
642 CreateSecurityPage(IN LPSECURITYINFO psi
)
645 PSECURITY_PAGE sPage
;
646 SI_OBJECT_INFO ObjectInfo
;
651 SetLastError(ERROR_INVALID_PARAMETER
);
653 DPRINT("No ISecurityInformation class passed!\n");
657 /* get the object information from the server interface */
658 hRet
= psi
->lpVtbl
->GetObjectInformation(psi
, &ObjectInfo
);
664 DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n");
668 if (!RegisterCheckListControl(hDllInstance
))
670 DPRINT("Registering the CHECKLIST_ACLUI class failed!\n");
674 sPage
= HeapAlloc(GetProcessHeap(),
676 sizeof(SECURITY_PAGE
));
679 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
681 DPRINT("Not enough memory to allocate a SECURITY_PAGE!\n");
685 sPage
->ObjectInfo
= ObjectInfo
;
687 ZeroMemory(&psp
, sizeof(psp
));
689 psp
.dwSize
= sizeof(PROPSHEETPAGE
);
690 psp
.dwFlags
= PSP_USECALLBACK
;
691 psp
.hInstance
= hDllInstance
;
692 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SECPAGE
);
693 psp
.pfnDlgProc
= SecurityPageProc
;
694 psp
.lParam
= (LPARAM
)sPage
;
695 psp
.pfnCallback
= SecurityPageCallback
;
697 if((ObjectInfo
.dwFlags
& SI_PAGE_TITLE
) &&
698 ObjectInfo
.pszPageTitle
!= NULL
&& ObjectInfo
.pszPageTitle
[0] != L
'\0')
700 /* Set the page title if the flag is present and the string isn't empty */
701 psp
.pszTitle
= ObjectInfo
.pszPageTitle
;
702 psp
.dwFlags
|= PSP_USETITLE
;
705 /* NOTE: the SECURITY_PAGE structure will be freed by the property page
708 return CreatePropertySheetPage(&psp
);
713 * EditSecurity EXPORTED
719 EditSecurity(IN HWND hwndOwner
,
720 IN LPSECURITYINFO psi
)
723 SI_OBJECT_INFO ObjectInfo
;
725 HPROPSHEETPAGE hPages
[1];
731 SetLastError(ERROR_INVALID_PARAMETER
);
733 DPRINT("No ISecurityInformation class passed!\n");
737 /* get the object information from the server interface */
738 hRet
= psi
->lpVtbl
->GetObjectInformation(psi
, &ObjectInfo
);
744 DPRINT("GetObjectInformation() failed!\n");
748 /* create the page */
749 hPages
[0] = CreateSecurityPage(psi
);
750 if(hPages
[0] == NULL
)
752 DPRINT("CreateSecurityPage(), couldn't create property sheet!\n");
756 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
757 psh
.dwFlags
= PSH_DEFAULT
;
758 psh
.hwndParent
= hwndOwner
;
759 psh
.hInstance
= hDllInstance
;
760 if((ObjectInfo
.dwFlags
& SI_PAGE_TITLE
) &&
761 ObjectInfo
.pszPageTitle
!= NULL
&& ObjectInfo
.pszPageTitle
[0] != L
'\0')
763 /* Set the page title if the flag is present and the string isn't empty */
764 psh
.pszCaption
= ObjectInfo
.pszPageTitle
;
765 psh
.dwFlags
|= PSH_PROPTITLE
;
770 /* Set the page title to the object name, make sure the format string
771 has "%1" NOT "%s" because it uses FormatMessage() to automatically
772 allocate the right amount of memory. */
773 LoadAndFormatString(hDllInstance
,
776 ObjectInfo
.pszObjectName
);
777 psh
.pszCaption
= lpCaption
;
780 psh
.nPages
= sizeof(hPages
) / sizeof(HPROPSHEETPAGE
);
784 Ret
= (PropertySheet(&psh
) != -1);
786 if(lpCaption
!= NULL
)
788 LocalFree((HLOCAL
)lpCaption
);
795 DllMain(IN HINSTANCE hinstDLL
,
797 IN LPVOID lpvReserved
)
801 case DLL_PROCESS_ATTACH
:
802 hDllInstance
= hinstDLL
;
804 case DLL_THREAD_ATTACH
:
805 case DLL_THREAD_DETACH
:
806 case DLL_PROCESS_DETACH
: