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 static INT_PTR CALLBACK
465 SecurityPageProc(IN HWND hwndDlg
,
476 NMHDR
*pnmh
= (NMHDR
*)lParam
;
477 if (pnmh
->idFrom
== IDC_ACELIST
)
479 sp
= (PSECURITY_PAGE
)GetWindowLongPtr(hwndDlg
,
485 case LVN_ITEMCHANGED
:
487 UpdateControlStates(sp
);
498 sp
= (PSECURITY_PAGE
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
505 sp
->hWndAceList
= GetDlgItem(hwndDlg
, IDC_ACELIST
);
506 sp
->hBtnRemove
= GetDlgItem(hwndDlg
, IDC_ACELIST_REMOVE
);
507 sp
->hAceCheckList
= GetDlgItem(hwndDlg
, IDC_ACE_CHECKLIST
);
509 /* save the pointer to the structure */
510 SetWindowLongPtr(hwndDlg
,
514 sp
->hiUsrs
= ImageList_LoadBitmap(hDllInstance
,
515 MAKEINTRESOURCE(IDB_USRGRPIMAGES
),
520 /* setup the listview control */
521 ListView_SetExtendedListViewStyleEx(sp
->hWndAceList
,
522 LVS_EX_FULLROWSELECT
,
523 LVS_EX_FULLROWSELECT
);
524 ListView_SetImageList(sp
->hWndAceList
,
528 GetClientRect(sp
->hWndAceList
, &rcLvClient
);
530 /* add a column to the list view */
531 lvc
.mask
= LVCF_FMT
| LVCF_WIDTH
;
532 lvc
.fmt
= LVCFMT_LEFT
;
533 lvc
.cx
= rcLvClient
.right
;
534 ListView_InsertColumn(sp
->hWndAceList
, 0, &lvc
);
536 FillUsersGroupsList(sp
);
538 ListViewSelectItem(sp
->hWndAceList
,
541 /* calculate the columns of the allow/deny checkboxes */
542 SetAceCheckListColumns(sp
->hAceCheckList
,
544 GetDlgItem(hwndDlg
, IDC_LABEL_ALLOW
));
545 SetAceCheckListColumns(sp
->hAceCheckList
,
547 GetDlgItem(hwndDlg
, IDC_LABEL_DENY
));
549 /* FIXME - hide controls in case the flags aren't present */
559 * CreateSecurityPage EXPORTED
565 CreateSecurityPage(IN LPSECURITYINFO psi
)
568 PSECURITY_PAGE sPage
;
569 SI_OBJECT_INFO ObjectInfo
;
574 SetLastError(ERROR_INVALID_PARAMETER
);
576 DPRINT("No ISecurityInformation class passed!\n");
580 /* get the object information from the server interface */
581 hRet
= psi
->lpVtbl
->GetObjectInformation(psi
, &ObjectInfo
);
587 DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n");
591 if (!RegisterCheckListControl(hDllInstance
))
593 DPRINT("Registering the CHECKLIST_ACLUI class failed!\n");
597 sPage
= HeapAlloc(GetProcessHeap(),
599 sizeof(SECURITY_PAGE
));
602 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
604 DPRINT("Not enough memory to allocate a SECURITY_PAGE!\n");
608 sPage
->ObjectInfo
= ObjectInfo
;
610 psp
.dwSize
= sizeof(PROPSHEETPAGE
);
611 psp
.dwFlags
= PSP_USECALLBACK
;
612 psp
.hInstance
= hDllInstance
;
613 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SECPAGE
);
614 psp
.pfnDlgProc
= SecurityPageProc
;
615 psp
.lParam
= (LPARAM
)sPage
;
616 psp
.pfnCallback
= SecurityPageCallback
;
618 if((ObjectInfo
.dwFlags
& SI_PAGE_TITLE
) &&
619 ObjectInfo
.pszPageTitle
!= NULL
&& ObjectInfo
.pszPageTitle
[0] != L
'\0')
621 /* Set the page title if the flag is present and the string isn't empty */
622 psp
.pszTitle
= ObjectInfo
.pszPageTitle
;
623 psp
.dwFlags
|= PSP_USETITLE
;
626 /* NOTE: the SECURITY_PAGE structure will be freed by the property page
629 return CreatePropertySheetPage(&psp
);
634 * EditSecurity EXPORTED
640 EditSecurity(IN HWND hwndOwner
,
641 IN LPSECURITYINFO psi
)
644 SI_OBJECT_INFO ObjectInfo
;
646 HPROPSHEETPAGE hPages
[1];
652 SetLastError(ERROR_INVALID_PARAMETER
);
654 DPRINT("No ISecurityInformation class passed!\n");
658 /* get the object information from the server interface */
659 hRet
= psi
->lpVtbl
->GetObjectInformation(psi
, &ObjectInfo
);
665 DPRINT("GetObjectInformation() failed!\n");
669 /* create the page */
670 hPages
[0] = CreateSecurityPage(psi
);
671 if(hPages
[0] == NULL
)
673 DPRINT("CreateSecurityPage(), couldn't create property sheet!\n");
677 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
678 psh
.dwFlags
= PSH_DEFAULT
;
679 psh
.hwndParent
= hwndOwner
;
680 psh
.hInstance
= hDllInstance
;
681 if((ObjectInfo
.dwFlags
& SI_PAGE_TITLE
) &&
682 ObjectInfo
.pszPageTitle
!= NULL
&& ObjectInfo
.pszPageTitle
[0] != L
'\0')
684 /* Set the page title if the flag is present and the string isn't empty */
685 psh
.pszCaption
= ObjectInfo
.pszPageTitle
;
690 /* Set the page title to the object name, make sure the format string
691 has "%1" NOT "%s" because it uses FormatMessage() to automatically
692 allocate the right amount of memory. */
693 LoadAndFormatString(hDllInstance
,
696 ObjectInfo
.pszObjectName
);
697 psh
.pszCaption
= lpCaption
;
700 psh
.nPages
= sizeof(hPages
) / sizeof(HPROPSHEETPAGE
);
704 Ret
= (PropertySheet(&psh
) != -1);
706 if(lpCaption
!= NULL
)
708 LocalFree((HLOCAL
)lpCaption
);
715 DllMain(IN HINSTANCE hinstDLL
,
717 IN LPVOID lpvReserved
)
721 case DLL_PROCESS_ATTACH
:
722 hDllInstance
= hinstDLL
;
724 case DLL_THREAD_ATTACH
:
725 case DLL_THREAD_DETACH
:
726 case DLL_PROCESS_DETACH
: