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 ListViewGetSelectedItemData(IN HWND hwnd
)
38 Index
= ListView_GetNextItem(hwnd
,
49 if (ListView_GetItem(hwnd
,
60 DestroySecurityPage(IN PSECURITY_PAGE sp
)
62 if(sp
->hiUsrs
!= NULL
)
64 ImageList_Destroy(sp
->hiUsrs
);
67 HeapFree(GetProcessHeap(),
73 FreeAceList(IN PACE_LISTITEM
*AceListHead
)
75 PACE_LISTITEM CurItem
, NextItem
;
77 CurItem
= *AceListHead
;
78 while (CurItem
!= NULL
)
80 /* free the SID string if present */
81 if (CurItem
->DisplayString
!= NULL
)
83 LocalFree((HLOCAL
)CurItem
->DisplayString
);
86 /* free the ACE list item */
87 NextItem
= CurItem
->Next
;
88 HeapFree(GetProcessHeap(),
98 FindSidInAceList(IN PACE_LISTITEM AceListHead
,
101 PACE_LISTITEM CurItem
;
103 for (CurItem
= AceListHead
;
105 CurItem
= CurItem
->Next
)
107 if (EqualSid((PSID
)(CurItem
+ 1),
118 ReloadUsersGroupsList(IN PSECURITY_PAGE sp
)
120 PSECURITY_DESCRIPTOR SecurityDescriptor
;
121 BOOL DaclPresent
, DaclDefaulted
;
125 /* delete the cached ACL */
126 FreeAceList(&sp
->AceListHead
);
129 hRet
= sp
->psi
->lpVtbl
->GetSecurity(sp
->psi
,
130 DACL_SECURITY_INFORMATION
,
133 if (SUCCEEDED(hRet
) && SecurityDescriptor
!= NULL
)
135 if (GetSecurityDescriptorDacl(SecurityDescriptor
,
140 PACE_LISTITEM AceListItem
, *NextAcePtr
;
144 DWORD AccountNameSize
, DomainNameSize
, SidLength
;
145 SID_NAME_USE SidNameUse
;
148 NextAcePtr
= &sp
->AceListHead
;
151 AceIndex
< Dacl
->AceCount
;
158 Sid
= (PSID
)&((PACCESS_ALLOWED_ACE
)Ace
)->SidStart
;
160 if (!FindSidInAceList(sp
->AceListHead
,
163 SidLength
= GetLengthSid(Sid
);
168 /* calculate the size of the buffer we need to calculate */
169 LookupAccountSid(NULL
, /* FIXME */
177 /* allocate the ace */
178 AceListItem
= HeapAlloc(GetProcessHeap(),
180 sizeof(ACE_LISTITEM
) +
182 ((AccountNameSize
+ DomainNameSize
) * sizeof(WCHAR
)));
183 if (AceListItem
!= NULL
)
185 AceListItem
->AccountName
= (LPWSTR
)((ULONG_PTR
)(AceListItem
+ 1) + SidLength
);
186 AceListItem
->DomainName
= AceListItem
->AccountName
+ AccountNameSize
;
189 (PSID
)(AceListItem
+ 1),
192 LookupResult
= ERROR_SUCCESS
;
193 if (!LookupAccountSid(NULL
, /* FIXME */
195 AceListItem
->AccountName
,
197 AceListItem
->DomainName
,
201 LookupResult
= GetLastError();
202 if (LookupResult
!= ERROR_NONE_MAPPED
)
204 HeapFree(GetProcessHeap(),
211 if (AccountNameSize
== 0)
213 AceListItem
->AccountName
= NULL
;
215 if (DomainNameSize
== 0)
217 AceListItem
->DomainName
= NULL
;
220 AceListItem
->Next
= NULL
;
221 if (LookupResult
== ERROR_NONE_MAPPED
)
223 if (!ConvertSidToStringSid(Sid
,
224 &AceListItem
->DisplayString
))
226 AceListItem
->DisplayString
= NULL
;
231 LSA_HANDLE LsaHandle
;
234 AceListItem
->DisplayString
= NULL
;
236 /* read the domain of the SID */
237 if (OpenLSAPolicyHandle(NULL
, /* FIXME */
238 POLICY_LOOKUP_NAMES
| POLICY_VIEW_LOCAL_INFORMATION
,
241 PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain
;
242 PLSA_TRANSLATED_NAME Names
;
243 PLSA_TRUST_INFORMATION Domain
;
244 PLSA_UNICODE_STRING DomainName
;
245 PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo
= NULL
;
247 Status
= LsaLookupSids(LsaHandle
,
252 if (NT_SUCCESS(Status
))
254 if (ReferencedDomain
!= NULL
&&
255 Names
->DomainIndex
>= 0)
257 Domain
= &ReferencedDomain
->Domains
[Names
->DomainIndex
];
258 DomainName
= &Domain
->Name
;
266 AceListItem
->SidNameUse
= Names
->Use
;
273 /* query the domain name for BUILTIN accounts */
274 Status
= LsaQueryInformationPolicy(LsaHandle
,
275 PolicyAccountDomainInformation
,
276 (PVOID
*)&PolicyAccountDomainInfo
);
277 if (NT_SUCCESS(Status
))
279 DomainName
= &PolicyAccountDomainInfo
->DomainName
;
281 /* make the user believe this is a group */
282 AceListItem
->SidNameUse
= SidTypeGroup
;
291 AceListItem
->DisplayString
= (LPWSTR
)LocalAlloc(LMEM_FIXED
,
292 (AccountNameSize
* sizeof(WCHAR
)) +
293 (DomainName
->Length
+ sizeof(WCHAR
)) +
294 (Names
->Name
.Length
+ sizeof(WCHAR
)) +
295 (4 * sizeof(WCHAR
)));
296 if (AceListItem
->DisplayString
!= NULL
)
300 /* NOTE: LSA_UNICODE_STRINGs are not always NULL-terminated! */
302 wcscpy(AceListItem
->DisplayString
,
303 AceListItem
->AccountName
);
304 wcscat(AceListItem
->DisplayString
,
306 s
= AceListItem
->DisplayString
+ wcslen(AceListItem
->DisplayString
);
310 s
+= DomainName
->Length
/ sizeof(WCHAR
);
315 s
+= Names
->Name
.Length
/ sizeof(WCHAR
);
320 /* mark the ace as a user unless it's a
322 if (PolicyAccountDomainInfo
== NULL
)
324 AceListItem
->SidNameUse
= SidTypeUser
;
330 case SidTypeWellKnownGroup
:
332 /* make the user believe this is a group */
333 AceListItem
->SidNameUse
= SidTypeGroup
;
343 if (PolicyAccountDomainInfo
!= NULL
)
345 LsaFreeMemory(PolicyAccountDomainInfo
);
348 LsaFreeMemory(ReferencedDomain
);
349 LsaFreeMemory(Names
);
355 /* append item to the cached ACL */
356 *NextAcePtr
= AceListItem
;
357 NextAcePtr
= &AceListItem
->Next
;
362 LocalFree((HLOCAL
)SecurityDescriptor
);
367 FillUsersGroupsList(IN PSECURITY_PAGE sp
)
370 PACE_LISTITEM CurItem
;
373 SelLParam
= ListViewGetSelectedItemData(sp
->hWndAceList
);
375 DisableRedrawWindow(sp
->hWndAceList
);
377 ListView_DeleteAllItems(sp
->hWndAceList
);
379 ReloadUsersGroupsList(sp
);
381 for (CurItem
= sp
->AceListHead
;
383 CurItem
= CurItem
->Next
)
387 li
.mask
= LVIF_IMAGE
| LVIF_PARAM
| LVIF_STATE
| LVIF_TEXT
;
390 li
.state
= (CurItem
== (PACE_LISTITEM
)SelLParam
? LVIS_SELECTED
: 0);
391 li
.stateMask
= LVIS_SELECTED
;
392 li
.pszText
= (CurItem
->DisplayString
!= NULL
? CurItem
->DisplayString
: CurItem
->AccountName
);
393 switch (CurItem
->SidNameUse
)
405 li
.lParam
= (LPARAM
)CurItem
;
407 ListView_InsertItem(sp
->hWndAceList
,
411 EnableRedrawWindow(sp
->hWndAceList
);
413 GetClientRect(sp
->hWndAceList
, &rcLvClient
);
415 ListView_SetColumnWidth(sp
->hWndAceList
,
422 SecurityPageCallback(IN HWND hwnd
,
424 IN LPPROPSHEETPAGE ppsp
)
426 PSECURITY_PAGE sp
= (PSECURITY_PAGE
)ppsp
->lParam
;
436 DestroySecurityPage(sp
);
445 static INT_PTR CALLBACK
446 SecurityPageProc(IN HWND hwndDlg
,
457 sp
= (PSECURITY_PAGE
)((LPPROPSHEETPAGE
)lParam
)->lParam
;
464 sp
->hWndAceList
= GetDlgItem(hwndDlg
, IDC_ACELIST
);
466 /* save the pointer to the structure */
467 SetWindowLongPtr(hwndDlg
,
471 sp
->hiUsrs
= ImageList_LoadBitmap(hDllInstance
,
472 MAKEINTRESOURCE(IDB_USRGRPIMAGES
),
477 /* setup the listview control */
478 ListView_SetExtendedListViewStyleEx(sp
->hWndAceList
,
479 LVS_EX_FULLROWSELECT
,
480 LVS_EX_FULLROWSELECT
);
481 ListView_SetImageList(sp
->hWndAceList
,
485 GetClientRect(sp
->hWndAceList
, &rcLvClient
);
487 /* add a column to the list view */
488 lvc
.mask
= LVCF_FMT
| LVCF_WIDTH
;
489 lvc
.fmt
= LVCFMT_LEFT
;
490 lvc
.cx
= rcLvClient
.right
;
491 ListView_InsertColumn(sp
->hWndAceList
, 0, &lvc
);
493 FillUsersGroupsList(sp
);
495 /* FIXME - hide controls in case the flags aren't present */
505 * CreateSecurityPage EXPORTED
511 CreateSecurityPage(IN LPSECURITYINFO psi
)
514 PSECURITY_PAGE sPage
;
515 SI_OBJECT_INFO ObjectInfo
;
520 SetLastError(ERROR_INVALID_PARAMETER
);
522 DPRINT("No ISecurityInformation class passed!\n");
526 /* get the object information from the server interface */
527 hRet
= psi
->lpVtbl
->GetObjectInformation(psi
, &ObjectInfo
);
533 DPRINT("CreateSecurityPage() failed!\n");
537 sPage
= HeapAlloc(GetProcessHeap(),
539 sizeof(SECURITY_PAGE
));
542 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
544 DPRINT("Not enough memory to allocate a SECURITY_PAGE!\n");
548 sPage
->ObjectInfo
= ObjectInfo
;
550 psp
.dwSize
= sizeof(PROPSHEETPAGE
);
551 psp
.dwFlags
= PSP_USECALLBACK
;
552 psp
.hInstance
= hDllInstance
;
553 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SECPAGE
);
554 psp
.pfnDlgProc
= SecurityPageProc
;
555 psp
.lParam
= (LPARAM
)sPage
;
556 psp
.pfnCallback
= SecurityPageCallback
;
558 if((ObjectInfo
.dwFlags
& SI_PAGE_TITLE
) != 0 &&
559 ObjectInfo
.pszPageTitle
!= NULL
&& ObjectInfo
.pszPageTitle
[0] != L
'\0')
561 /* Set the page title if the flag is present and the string isn't empty */
562 psp
.pszTitle
= ObjectInfo
.pszPageTitle
;
563 psp
.dwFlags
|= PSP_USETITLE
;
566 /* NOTE: the SECURITY_PAGE structure will be freed by the property page
569 return CreatePropertySheetPage(&psp
);
574 * EditSecurity EXPORTED
580 EditSecurity(IN HWND hwndOwner
,
581 IN LPSECURITYINFO psi
)
584 SI_OBJECT_INFO ObjectInfo
;
586 HPROPSHEETPAGE hPages
[1];
592 SetLastError(ERROR_INVALID_PARAMETER
);
594 DPRINT("No ISecurityInformation class passed!\n");
598 /* get the object information from the server interface */
599 hRet
= psi
->lpVtbl
->GetObjectInformation(psi
, &ObjectInfo
);
605 DPRINT("GetObjectInformation() failed!\n");
609 /* create the page */
610 hPages
[0] = CreateSecurityPage(psi
);
611 if(hPages
[0] == NULL
)
613 DPRINT("CreateSecurityPage(), couldn't create property sheet!\n");
617 psh
.dwSize
= sizeof(PROPSHEETHEADER
);
618 psh
.dwFlags
= PSH_DEFAULT
;
619 psh
.hwndParent
= hwndOwner
;
620 psh
.hInstance
= hDllInstance
;
621 if((ObjectInfo
.dwFlags
& SI_PAGE_TITLE
) != 0 &&
622 ObjectInfo
.pszPageTitle
!= NULL
&& ObjectInfo
.pszPageTitle
[0] != L
'\0')
624 /* Set the page title if the flag is present and the string isn't empty */
625 psh
.pszCaption
= ObjectInfo
.pszPageTitle
;
630 /* Set the page title to the object name, make sure the format string
631 has "%1" NOT "%s" because it uses FormatMessage() to automatically
632 allocate the right amount of memory. */
633 LoadAndFormatString(hDllInstance
,
636 ObjectInfo
.pszObjectName
);
637 psh
.pszCaption
= lpCaption
;
640 psh
.nPages
= sizeof(hPages
) / sizeof(HPROPSHEETPAGE
);
644 Ret
= (PropertySheet(&psh
) != -1);
646 if(lpCaption
!= NULL
)
648 LocalFree((HLOCAL
)lpCaption
);
655 DllMain(IN HINSTANCE hinstDLL
,
657 IN LPVOID lpvReserved
)
661 case DLL_PROCESS_ATTACH
:
662 hDllInstance
= hinstDLL
;
664 case DLL_THREAD_ATTACH
:
665 case DLL_THREAD_DETACH
:
666 case DLL_PROCESS_DETACH
: