query the dacl from the ISecurityInformation server, query the domains name from...
[reactos.git] / reactos / lib / aclui / aclui.c
1 /*
2 * ReactOS Access Control List Editor
3 * Copyright (C) 2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "acluilib.h"
30
31 HINSTANCE hDllInstance;
32
33 static LPARAM
34 ListViewGetSelectedItemData(IN HWND hwnd)
35 {
36 int Index;
37
38 Index = ListView_GetNextItem(hwnd,
39 -1,
40 LVNI_SELECTED);
41 if (Index != -1)
42 {
43 LVITEM li;
44
45 li.mask = LVIF_PARAM;
46 li.iItem = Index;
47 li.iSubItem = 0;
48
49 if (ListView_GetItem(hwnd,
50 &li))
51 {
52 return li.lParam;
53 }
54 }
55
56 return 0;
57 }
58
59 static VOID
60 DestroySecurityPage(IN PSECURITY_PAGE sp)
61 {
62 if(sp->hiUsrs != NULL)
63 {
64 ImageList_Destroy(sp->hiUsrs);
65 }
66
67 HeapFree(GetProcessHeap(),
68 0,
69 sp);
70 }
71
72 static VOID
73 FreeAceList(IN PACE_LISTITEM *AceListHead)
74 {
75 PACE_LISTITEM CurItem, NextItem;
76
77 CurItem = *AceListHead;
78 while (CurItem != NULL)
79 {
80 /* free the SID string if present */
81 if (CurItem->DisplayString != NULL)
82 {
83 LocalFree((HLOCAL)CurItem->DisplayString);
84 }
85
86 /* free the ACE list item */
87 NextItem = CurItem->Next;
88 HeapFree(GetProcessHeap(),
89 0,
90 CurItem);
91 CurItem = NextItem;
92 }
93
94 *AceListHead = NULL;
95 }
96
97 static PACE_LISTITEM
98 FindSidInAceList(IN PACE_LISTITEM AceListHead,
99 IN PSID Sid)
100 {
101 PACE_LISTITEM CurItem;
102
103 for (CurItem = AceListHead;
104 CurItem != NULL;
105 CurItem = CurItem->Next)
106 {
107 if (EqualSid((PSID)(CurItem + 1),
108 Sid))
109 {
110 return CurItem;
111 }
112 }
113
114 return NULL;
115 }
116
117 static VOID
118 ReloadUsersGroupsList(IN PSECURITY_PAGE sp)
119 {
120 PSECURITY_DESCRIPTOR SecurityDescriptor;
121 BOOL DaclPresent, DaclDefaulted;
122 PACL Dacl = NULL;
123 HRESULT hRet;
124
125 /* delete the cached ACL */
126 FreeAceList(&sp->AceListHead);
127
128 /* query the ACL */
129 hRet = sp->psi->lpVtbl->GetSecurity(sp->psi,
130 DACL_SECURITY_INFORMATION,
131 &SecurityDescriptor,
132 FALSE);
133 if (SUCCEEDED(hRet) && SecurityDescriptor != NULL)
134 {
135 if (GetSecurityDescriptorDacl(SecurityDescriptor,
136 &DaclPresent,
137 &Dacl,
138 &DaclDefaulted))
139 {
140 PACE_LISTITEM AceListItem, *NextAcePtr;
141 PSID Sid;
142 PVOID Ace;
143 ULONG AceIndex;
144 DWORD AccountNameSize, DomainNameSize, SidLength;
145 SID_NAME_USE SidNameUse;
146 DWORD LookupResult;
147
148 NextAcePtr = &sp->AceListHead;
149
150 for (AceIndex = 0;
151 AceIndex < Dacl->AceCount;
152 AceIndex++)
153 {
154 GetAce(Dacl,
155 AceIndex,
156 &Ace);
157
158 Sid = (PSID)&((PACCESS_ALLOWED_ACE)Ace)->SidStart;
159
160 if (!FindSidInAceList(sp->AceListHead,
161 Sid))
162 {
163 SidLength = GetLengthSid(Sid);
164
165 AccountNameSize = 0;
166 DomainNameSize = 0;
167
168 /* calculate the size of the buffer we need to calculate */
169 LookupAccountSid(NULL, /* FIXME */
170 Sid,
171 NULL,
172 &AccountNameSize,
173 NULL,
174 &DomainNameSize,
175 &SidNameUse);
176
177 /* allocate the ace */
178 AceListItem = HeapAlloc(GetProcessHeap(),
179 0,
180 sizeof(ACE_LISTITEM) +
181 SidLength +
182 ((AccountNameSize + DomainNameSize) * sizeof(WCHAR)));
183 if (AceListItem != NULL)
184 {
185 AceListItem->AccountName = (LPWSTR)((ULONG_PTR)(AceListItem + 1) + SidLength);
186 AceListItem->DomainName = AceListItem->AccountName + AccountNameSize;
187
188 CopySid(SidLength,
189 (PSID)(AceListItem + 1),
190 Sid);
191
192 LookupResult = ERROR_SUCCESS;
193 if (!LookupAccountSid(NULL, /* FIXME */
194 Sid,
195 AceListItem->AccountName,
196 &AccountNameSize,
197 AceListItem->DomainName,
198 &DomainNameSize,
199 &SidNameUse))
200 {
201 LookupResult = GetLastError();
202 if (LookupResult != ERROR_NONE_MAPPED)
203 {
204 HeapFree(GetProcessHeap(),
205 0,
206 AceListItem);
207 continue;
208 }
209 }
210
211 if (AccountNameSize == 0)
212 {
213 AceListItem->AccountName = NULL;
214 }
215 if (DomainNameSize == 0)
216 {
217 AceListItem->DomainName = NULL;
218 }
219
220 AceListItem->Next = NULL;
221 if (LookupResult == ERROR_NONE_MAPPED)
222 {
223 if (!ConvertSidToStringSid(Sid,
224 &AceListItem->DisplayString))
225 {
226 AceListItem->DisplayString = NULL;
227 }
228 }
229 else
230 {
231 LSA_HANDLE LsaHandle;
232 NTSTATUS Status;
233
234 AceListItem->DisplayString = NULL;
235
236 /* read the domain of the SID */
237 if (OpenLSAPolicyHandle(NULL, /* FIXME */
238 POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
239 &LsaHandle))
240 {
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;
246
247 Status = LsaLookupSids(LsaHandle,
248 1,
249 &Sid,
250 &ReferencedDomain,
251 &Names);
252 if (NT_SUCCESS(Status))
253 {
254 if (ReferencedDomain != NULL &&
255 Names->DomainIndex >= 0)
256 {
257 Domain = &ReferencedDomain->Domains[Names->DomainIndex];
258 DomainName = &Domain->Name;
259 }
260 else
261 {
262 Domain = NULL;
263 DomainName = NULL;
264 }
265
266 AceListItem->SidNameUse = Names->Use;
267
268 switch (Names->Use)
269 {
270 case SidTypeAlias:
271 if (Domain != NULL)
272 {
273 /* query the domain name for BUILTIN accounts */
274 Status = LsaQueryInformationPolicy(LsaHandle,
275 PolicyAccountDomainInformation,
276 (PVOID*)&PolicyAccountDomainInfo);
277 if (NT_SUCCESS(Status))
278 {
279 DomainName = &PolicyAccountDomainInfo->DomainName;
280
281 /* make the user believe this is a group */
282 AceListItem->SidNameUse = SidTypeGroup;
283 }
284 }
285 /* fall through */
286
287 case SidTypeUser:
288 {
289 if (Domain != NULL)
290 {
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)
297 {
298 WCHAR *s;
299
300 /* NOTE: LSA_UNICODE_STRINGs are not always NULL-terminated! */
301
302 wcscpy(AceListItem->DisplayString,
303 AceListItem->AccountName);
304 wcscat(AceListItem->DisplayString,
305 L" (");
306 s = AceListItem->DisplayString + wcslen(AceListItem->DisplayString);
307 CopyMemory(s,
308 DomainName->Buffer,
309 DomainName->Length);
310 s += DomainName->Length / sizeof(WCHAR);
311 *(s++) = L'\\';
312 CopyMemory(s,
313 Names->Name.Buffer,
314 Names->Name.Length);
315 s += Names->Name.Length / sizeof(WCHAR);
316 *(s++) = L')';
317 *s = L'\0';
318 }
319
320 /* mark the ace as a user unless it's a
321 BUILTIN account */
322 if (PolicyAccountDomainInfo == NULL)
323 {
324 AceListItem->SidNameUse = SidTypeUser;
325 }
326 }
327 break;
328 }
329
330 case SidTypeWellKnownGroup:
331 {
332 /* make the user believe this is a group */
333 AceListItem->SidNameUse = SidTypeGroup;
334 break;
335 }
336
337 default:
338 {
339 break;
340 }
341 }
342
343 if (PolicyAccountDomainInfo != NULL)
344 {
345 LsaFreeMemory(PolicyAccountDomainInfo);
346 }
347
348 LsaFreeMemory(ReferencedDomain);
349 LsaFreeMemory(Names);
350 }
351 LsaClose(LsaHandle);
352 }
353 }
354
355 /* append item to the cached ACL */
356 *NextAcePtr = AceListItem;
357 NextAcePtr = &AceListItem->Next;
358 }
359 }
360 }
361 }
362 LocalFree((HLOCAL)SecurityDescriptor);
363 }
364 }
365
366 static VOID
367 FillUsersGroupsList(IN PSECURITY_PAGE sp)
368 {
369 LPARAM SelLParam;
370 PACE_LISTITEM CurItem;
371 RECT rcLvClient;
372
373 SelLParam = ListViewGetSelectedItemData(sp->hWndAceList);
374
375 DisableRedrawWindow(sp->hWndAceList);
376
377 ListView_DeleteAllItems(sp->hWndAceList);
378
379 ReloadUsersGroupsList(sp);
380
381 for (CurItem = sp->AceListHead;
382 CurItem != NULL;
383 CurItem = CurItem->Next)
384 {
385 LVITEM li;
386
387 li.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
388 li.iItem = -1;
389 li.iSubItem = 0;
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)
394 {
395 case SidTypeUser:
396 li.iImage = 0;
397 break;
398 case SidTypeGroup:
399 li.iImage = 1;
400 break;
401 default:
402 li.iImage = -1;
403 break;
404 }
405 li.lParam = (LPARAM)CurItem;
406
407 ListView_InsertItem(sp->hWndAceList,
408 &li);
409 }
410
411 EnableRedrawWindow(sp->hWndAceList);
412
413 GetClientRect(sp->hWndAceList, &rcLvClient);
414
415 ListView_SetColumnWidth(sp->hWndAceList,
416 0,
417 rcLvClient.right);
418 }
419
420
421 static UINT CALLBACK
422 SecurityPageCallback(IN HWND hwnd,
423 IN UINT uMsg,
424 IN LPPROPSHEETPAGE ppsp)
425 {
426 PSECURITY_PAGE sp = (PSECURITY_PAGE)ppsp->lParam;
427
428 switch(uMsg)
429 {
430 case PSPCB_CREATE:
431 {
432 return TRUE;
433 }
434 case PSPCB_RELEASE:
435 {
436 DestroySecurityPage(sp);
437 return FALSE;
438 }
439 }
440
441 return FALSE;
442 }
443
444
445 static INT_PTR CALLBACK
446 SecurityPageProc(IN HWND hwndDlg,
447 IN UINT uMsg,
448 IN WPARAM wParam,
449 IN LPARAM lParam)
450 {
451 PSECURITY_PAGE sp;
452
453 switch(uMsg)
454 {
455 case WM_INITDIALOG:
456 {
457 sp = (PSECURITY_PAGE)((LPPROPSHEETPAGE)lParam)->lParam;
458 if(sp != NULL)
459 {
460 LV_COLUMN lvc;
461 RECT rcLvClient;
462
463 sp->hWnd = hwndDlg;
464 sp->hWndAceList = GetDlgItem(hwndDlg, IDC_ACELIST);
465
466 /* save the pointer to the structure */
467 SetWindowLongPtr(hwndDlg,
468 DWL_USER,
469 (DWORD_PTR)sp);
470
471 sp->hiUsrs = ImageList_LoadBitmap(hDllInstance,
472 MAKEINTRESOURCE(IDB_USRGRPIMAGES),
473 16,
474 3,
475 0);
476
477 /* setup the listview control */
478 ListView_SetExtendedListViewStyleEx(sp->hWndAceList,
479 LVS_EX_FULLROWSELECT,
480 LVS_EX_FULLROWSELECT);
481 ListView_SetImageList(sp->hWndAceList,
482 sp->hiUsrs,
483 LVSIL_SMALL);
484
485 GetClientRect(sp->hWndAceList, &rcLvClient);
486
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);
492
493 FillUsersGroupsList(sp);
494
495 /* FIXME - hide controls in case the flags aren't present */
496 }
497 break;
498 }
499 }
500 return 0;
501 }
502
503
504 /*
505 * CreateSecurityPage EXPORTED
506 *
507 * @implemented
508 */
509 HPROPSHEETPAGE
510 WINAPI
511 CreateSecurityPage(IN LPSECURITYINFO psi)
512 {
513 PROPSHEETPAGE psp;
514 PSECURITY_PAGE sPage;
515 SI_OBJECT_INFO ObjectInfo;
516 HRESULT hRet;
517
518 if(psi == NULL)
519 {
520 SetLastError(ERROR_INVALID_PARAMETER);
521
522 DPRINT("No ISecurityInformation class passed!\n");
523 return NULL;
524 }
525
526 /* get the object information from the server interface */
527 hRet = psi->lpVtbl->GetObjectInformation(psi, &ObjectInfo);
528
529 if(FAILED(hRet))
530 {
531 SetLastError(hRet);
532
533 DPRINT("CreateSecurityPage() failed!\n");
534 return NULL;
535 }
536
537 sPage = HeapAlloc(GetProcessHeap(),
538 HEAP_ZERO_MEMORY,
539 sizeof(SECURITY_PAGE));
540 if (sPage == NULL)
541 {
542 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
543
544 DPRINT("Not enough memory to allocate a SECURITY_PAGE!\n");
545 return NULL;
546 }
547 sPage->psi = psi;
548 sPage->ObjectInfo = ObjectInfo;
549
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;
557
558 if((ObjectInfo.dwFlags & SI_PAGE_TITLE) != 0 &&
559 ObjectInfo.pszPageTitle != NULL && ObjectInfo.pszPageTitle[0] != L'\0')
560 {
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;
564 }
565
566 /* NOTE: the SECURITY_PAGE structure will be freed by the property page
567 callback! */
568
569 return CreatePropertySheetPage(&psp);
570 }
571
572
573 /*
574 * EditSecurity EXPORTED
575 *
576 * @implemented
577 */
578 BOOL
579 WINAPI
580 EditSecurity(IN HWND hwndOwner,
581 IN LPSECURITYINFO psi)
582 {
583 HRESULT hRet;
584 SI_OBJECT_INFO ObjectInfo;
585 PROPSHEETHEADER psh;
586 HPROPSHEETPAGE hPages[1];
587 LPWSTR lpCaption;
588 BOOL Ret;
589
590 if(psi == NULL)
591 {
592 SetLastError(ERROR_INVALID_PARAMETER);
593
594 DPRINT("No ISecurityInformation class passed!\n");
595 return FALSE;
596 }
597
598 /* get the object information from the server interface */
599 hRet = psi->lpVtbl->GetObjectInformation(psi, &ObjectInfo);
600
601 if(FAILED(hRet))
602 {
603 SetLastError(hRet);
604
605 DPRINT("GetObjectInformation() failed!\n");
606 return FALSE;
607 }
608
609 /* create the page */
610 hPages[0] = CreateSecurityPage(psi);
611 if(hPages[0] == NULL)
612 {
613 DPRINT("CreateSecurityPage(), couldn't create property sheet!\n");
614 return FALSE;
615 }
616
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')
623 {
624 /* Set the page title if the flag is present and the string isn't empty */
625 psh.pszCaption = ObjectInfo.pszPageTitle;
626 lpCaption = NULL;
627 }
628 else
629 {
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,
634 IDS_PSP_TITLE,
635 &lpCaption,
636 ObjectInfo.pszObjectName);
637 psh.pszCaption = lpCaption;
638 }
639
640 psh.nPages = sizeof(hPages) / sizeof(HPROPSHEETPAGE);
641 psh.nStartPage = 0;
642 psh.phpage = hPages;
643
644 Ret = (PropertySheet(&psh) != -1);
645
646 if(lpCaption != NULL)
647 {
648 LocalFree((HLOCAL)lpCaption);
649 }
650
651 return Ret;
652 }
653
654 BOOL STDCALL
655 DllMain(IN HINSTANCE hinstDLL,
656 IN DWORD dwReason,
657 IN LPVOID lpvReserved)
658 {
659 switch (dwReason)
660 {
661 case DLL_PROCESS_ATTACH:
662 hDllInstance = hinstDLL;
663 break;
664 case DLL_THREAD_ATTACH:
665 case DLL_THREAD_DETACH:
666 case DLL_PROCESS_DETACH:
667 break;
668 }
669 return TRUE;
670 }
671