minor fixes
[reactos.git] / reactos / lib / aclui / aclui.c
1 /*
2 * ReactOS Access Control List Editor
3 * Copyright (C) 2004-2005 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 <precomp.h>
30
31 HINSTANCE hDllInstance;
32
33 static PSID
34 AceHeaderToSID(IN PACE_HEADER AceHeader)
35 {
36 PSID Sid = NULL;
37 switch (AceHeader->AceType)
38 {
39 case ACCESS_ALLOWED_ACE_TYPE:
40 Sid = (PSID)&((PACCESS_ALLOWED_ACE)AceHeader)->SidStart;
41 break;
42 #if 0
43 case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
44 Sid = (PSID)&((PACCESS_ALLOWED_CALLBACK_ACE)AceHeader)->SidStart;
45 break;
46 case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
47 Sid = (PSID)&((PACCESS_ALLOWED_CALLBACK_OBJECT_ACE)AceHeader)->SidStart;
48 break;
49 #endif
50 case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
51 Sid = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)AceHeader)->SidStart;
52 break;
53 case ACCESS_DENIED_ACE_TYPE:
54 Sid = (PSID)&((PACCESS_DENIED_ACE)AceHeader)->SidStart;
55 break;
56 #if 0
57 case ACCESS_DENIED_CALLBACK_ACE_TYPE:
58 Sid = (PSID)&((PACCESS_DENIED_CALLBACK_ACE)AceHeader)->SidStart;
59 break;
60 case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
61 Sid = (PSID)&((PACCESS_DENIED_CALLBACK_OBJECT_ACE)AceHeader)->SidStart;
62 break;
63 #endif
64 case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
65 Sid = (PSID)&((PACCESS_DENIED_OBJECT_ACE)AceHeader)->SidStart;
66 break;
67 }
68
69 return Sid;
70 }
71
72 static VOID
73 DestroySecurityPage(IN PSECURITY_PAGE sp)
74 {
75 if(sp->hiPrincipals != NULL)
76 {
77 ImageList_Destroy(sp->hiPrincipals);
78 }
79
80 HeapFree(GetProcessHeap(),
81 0,
82 sp);
83
84 CoUninitialize();
85 }
86
87 static VOID
88 FreePrincipalsList(IN PPRINCIPAL_LISTITEM *PrincipalsListHead)
89 {
90 PPRINCIPAL_LISTITEM CurItem, NextItem;
91 PACE_ENTRY AceEntry, NextAceEntry;
92
93 CurItem = *PrincipalsListHead;
94 while (CurItem != NULL)
95 {
96 /* Free all ACEs */
97 AceEntry = CurItem->ACEs;
98 while (AceEntry != NULL)
99 {
100 NextAceEntry = AceEntry->Next;
101 HeapFree(GetProcessHeap(),
102 0,
103 AceEntry);
104 AceEntry = NextAceEntry;
105 }
106
107 /* free the SID string if present */
108 if (CurItem->DisplayString != NULL)
109 {
110 LocalFree((HLOCAL)CurItem->DisplayString);
111 }
112
113 /* free the ACE list item */
114 NextItem = CurItem->Next;
115 HeapFree(GetProcessHeap(),
116 0,
117 CurItem);
118 CurItem = NextItem;
119 }
120
121 *PrincipalsListHead = NULL;
122 }
123
124 static PACE_ENTRY
125 AddAceToPrincipal(IN PPRINCIPAL_LISTITEM Principal,
126 IN PACE_HEADER AceHeader)
127 {
128 PACE_ENTRY AceEntry, *AceLink;
129
130 AceEntry = HeapAlloc(GetProcessHeap(),
131 0,
132 sizeof(ACE_ENTRY) + AceHeader->AceSize);
133 if (AceEntry != NULL)
134 {
135 AceEntry->Next = NULL;
136
137 /* copy the ACE */
138 CopyMemory(AceEntry + 1,
139 AceHeader,
140 AceHeader->AceSize);
141
142 /* append it to the list */
143 AceLink = &Principal->ACEs;
144 while (*AceLink != NULL)
145 {
146 AceLink = &(*AceLink)->Next;
147 }
148 *AceLink = AceEntry;
149 }
150
151 return AceEntry;
152 }
153
154 static PPRINCIPAL_LISTITEM
155 FindSidInPrincipalsListAddAce(IN PPRINCIPAL_LISTITEM PrincipalsListHead,
156 IN PSID Sid,
157 IN PACE_HEADER AceHeader)
158 {
159 PPRINCIPAL_LISTITEM CurItem;
160
161 for (CurItem = PrincipalsListHead;
162 CurItem != NULL;
163 CurItem = CurItem->Next)
164 {
165 if (EqualSid((PSID)(CurItem + 1),
166 Sid))
167 {
168 if (AddAceToPrincipal(CurItem,
169 AceHeader) != NULL)
170 {
171 return CurItem;
172 }
173
174 /* unable to add the ACE to the principal */
175 break;
176 }
177 }
178
179 return NULL;
180 }
181
182 static BOOL
183 AddPrincipalToList(IN PSECURITY_PAGE sp,
184 IN PSID Sid,
185 IN PACE_HEADER AceHeader)
186 {
187 PPRINCIPAL_LISTITEM PrincipalListItem = NULL;
188 PACE_ENTRY AceEntry = NULL;
189 BOOL Ret = FALSE;
190
191 if (!FindSidInPrincipalsListAddAce(sp->PrincipalsListHead,
192 Sid,
193 AceHeader))
194 {
195 DWORD SidLength, AccountNameSize, DomainNameSize;
196 SID_NAME_USE SidNameUse;
197 DWORD LookupResult;
198 PPRINCIPAL_LISTITEM PrincipalListItem, *PrincipalLink;
199
200 AccountNameSize = 0;
201 DomainNameSize = 0;
202
203 /* calculate the size of the buffer we need to calculate */
204 if (!LookupAccountSid(sp->ServerName,
205 Sid,
206 NULL,
207 &AccountNameSize,
208 NULL,
209 &DomainNameSize,
210 &SidNameUse))
211 {
212 LookupResult = GetLastError();
213 if (LookupResult != ERROR_NONE_MAPPED &&
214 LookupResult != ERROR_INSUFFICIENT_BUFFER)
215 {
216 goto Cleanup;
217 }
218 }
219
220 PrincipalLink = &sp->PrincipalsListHead;
221 while (*PrincipalLink != NULL)
222 {
223 PrincipalLink = &(*PrincipalLink)->Next;
224 }
225
226 SidLength = GetLengthSid(Sid);
227
228 /* allocate the principal */
229 PrincipalListItem = HeapAlloc(GetProcessHeap(),
230 0,
231 sizeof(PRINCIPAL_LISTITEM) + SidLength +
232 ((AccountNameSize + DomainNameSize) * sizeof(WCHAR)));
233 if (PrincipalListItem != NULL)
234 {
235 PrincipalListItem->AccountName = (LPWSTR)((ULONG_PTR)(PrincipalListItem + 1) + SidLength);
236 PrincipalListItem->DomainName = PrincipalListItem->AccountName + AccountNameSize;
237
238 CopySid(SidLength,
239 (PSID)(PrincipalListItem + 1),
240 Sid);
241
242 LookupResult = ERROR_SUCCESS;
243 if (!LookupAccountSid(sp->ServerName,
244 Sid,
245 PrincipalListItem->AccountName,
246 &AccountNameSize,
247 PrincipalListItem->DomainName,
248 &DomainNameSize,
249 &SidNameUse))
250 {
251 LookupResult = GetLastError();
252 if (LookupResult != ERROR_NONE_MAPPED)
253 {
254 goto Cleanup;
255 }
256 }
257
258 if (AccountNameSize == 0)
259 {
260 PrincipalListItem->AccountName = NULL;
261 }
262 if (DomainNameSize == 0)
263 {
264 PrincipalListItem->DomainName = NULL;
265 }
266
267 /* allocate some memory for the ACE and copy it */
268 AceEntry = HeapAlloc(GetProcessHeap(),
269 0,
270 sizeof(ACE_ENTRY) + AceHeader->AceSize);
271 if (AceEntry == NULL)
272 {
273 goto Cleanup;
274 }
275 AceEntry->Next = NULL;
276 CopyMemory(AceEntry + 1,
277 AceHeader,
278 AceHeader->AceSize);
279
280 /* add the ACE to the list */
281 PrincipalListItem->ACEs = AceEntry;
282
283 PrincipalListItem->Next = NULL;
284 Ret = TRUE;
285
286 if (LookupResult == ERROR_NONE_MAPPED)
287 {
288 if (!ConvertSidToStringSid(Sid,
289 &PrincipalListItem->DisplayString))
290 {
291 PrincipalListItem->DisplayString = NULL;
292 }
293 }
294 else
295 {
296 LSA_HANDLE LsaHandle;
297 NTSTATUS Status;
298
299 PrincipalListItem->DisplayString = NULL;
300
301 /* read the domain of the SID */
302 if (OpenLSAPolicyHandle(sp->ServerName,
303 POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
304 &LsaHandle))
305 {
306 PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain;
307 PLSA_TRANSLATED_NAME Names;
308 PLSA_TRUST_INFORMATION Domain;
309 PLSA_UNICODE_STRING DomainName;
310 PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
311
312 Status = LsaLookupSids(LsaHandle,
313 1,
314 &Sid,
315 &ReferencedDomain,
316 &Names);
317 if (NT_SUCCESS(Status))
318 {
319 if (ReferencedDomain != NULL &&
320 Names->DomainIndex >= 0)
321 {
322 Domain = &ReferencedDomain->Domains[Names->DomainIndex];
323 DomainName = &Domain->Name;
324 }
325 else
326 {
327 Domain = NULL;
328 DomainName = NULL;
329 }
330
331 PrincipalListItem->SidNameUse = Names->Use;
332
333 switch (Names->Use)
334 {
335 case SidTypeAlias:
336 if (Domain != NULL)
337 {
338 /* query the domain name for BUILTIN accounts */
339 Status = LsaQueryInformationPolicy(LsaHandle,
340 PolicyAccountDomainInformation,
341 (PVOID*)&PolicyAccountDomainInfo);
342 if (NT_SUCCESS(Status))
343 {
344 DomainName = &PolicyAccountDomainInfo->DomainName;
345
346 /* make the user believe this is a group */
347 PrincipalListItem->SidNameUse = SidTypeGroup;
348 }
349 }
350 /* fall through */
351
352 case SidTypeUser:
353 {
354 if (Domain != NULL)
355 {
356 SIZE_T Size = (AccountNameSize + DomainName->Length +
357 Names->Name.Length + 6) * sizeof(WCHAR);
358 PrincipalListItem->DisplayString = (LPWSTR)LocalAlloc(LMEM_FIXED,
359 Size);
360 if (PrincipalListItem->DisplayString != NULL)
361 {
362 WCHAR *s;
363
364 /* NOTE: LSA_UNICODE_STRINGs are not always NULL-terminated! */
365
366 wcscpy(PrincipalListItem->DisplayString,
367 PrincipalListItem->AccountName);
368 wcscat(PrincipalListItem->DisplayString,
369 L" (");
370 s = PrincipalListItem->DisplayString + wcslen(PrincipalListItem->DisplayString);
371 CopyMemory(s,
372 DomainName->Buffer,
373 DomainName->Length);
374 s += DomainName->Length / sizeof(WCHAR);
375 *(s++) = L'\\';
376 CopyMemory(s,
377 Names->Name.Buffer,
378 Names->Name.Length);
379 s += Names->Name.Length / sizeof(WCHAR);
380 *(s++) = L')';
381 *s = L'\0';
382 }
383 else
384 {
385 Ret = FALSE;
386 break;
387 }
388
389 /* mark the ace as a user unless it's a
390 BUILTIN account */
391 if (PolicyAccountDomainInfo == NULL)
392 {
393 PrincipalListItem->SidNameUse = SidTypeUser;
394 }
395 }
396 break;
397 }
398
399 case SidTypeWellKnownGroup:
400 {
401 /* make the user believe this is a group */
402 PrincipalListItem->SidNameUse = SidTypeGroup;
403 break;
404 }
405
406 default:
407 {
408 DPRINT("Unhandled SID type: 0x%x\n", Names->Use);
409 break;
410 }
411 }
412
413 if (PolicyAccountDomainInfo != NULL)
414 {
415 LsaFreeMemory(PolicyAccountDomainInfo);
416 }
417
418 LsaFreeMemory(ReferencedDomain);
419 LsaFreeMemory(Names);
420 }
421 LsaClose(LsaHandle);
422 }
423 }
424
425 if (Ret)
426 {
427 /* append item to the principals list */
428 *PrincipalLink = PrincipalListItem;
429 }
430 }
431 }
432
433 if (!Ret)
434 {
435 Cleanup:
436 if (PrincipalListItem != NULL)
437 {
438 if (PrincipalListItem->DisplayString != NULL)
439 {
440 LocalFree((HLOCAL)PrincipalListItem->DisplayString);
441 }
442
443 HeapFree(GetProcessHeap(),
444 0,
445 PrincipalListItem);
446 }
447
448 if (AceEntry != NULL)
449 {
450 HeapFree(GetProcessHeap(),
451 0,
452 AceEntry);
453 }
454 }
455
456 return Ret;
457 }
458
459 static VOID
460 ReloadPrincipalsList(IN PSECURITY_PAGE sp)
461 {
462 PSECURITY_DESCRIPTOR SecurityDescriptor;
463 BOOL DaclPresent, DaclDefaulted;
464 PACL Dacl = NULL;
465 HRESULT hRet;
466
467 /* delete the cached ACL */
468 FreePrincipalsList(&sp->PrincipalsListHead);
469
470 /* query the ACL */
471 hRet = sp->psi->lpVtbl->GetSecurity(sp->psi,
472 DACL_SECURITY_INFORMATION,
473 &SecurityDescriptor,
474 FALSE);
475 if (SUCCEEDED(hRet) && SecurityDescriptor != NULL)
476 {
477 if (GetSecurityDescriptorDacl(SecurityDescriptor,
478 &DaclPresent,
479 &Dacl,
480 &DaclDefaulted) &&
481 DaclPresent && Dacl != NULL)
482 {
483 PSID Sid;
484 PACE_HEADER AceHeader;
485 ULONG AceIndex;
486
487 for (AceIndex = 0;
488 AceIndex < Dacl->AceCount;
489 AceIndex++)
490 {
491 if (GetAce(Dacl,
492 AceIndex,
493 (LPVOID*)&AceHeader) &&
494 AceHeader != NULL)
495 {
496 Sid = AceHeaderToSID(AceHeader);
497
498 AddPrincipalToList(sp,
499 Sid,
500 AceHeader);
501 }
502 }
503 }
504 LocalFree((HLOCAL)SecurityDescriptor);
505 }
506 }
507
508 static INT
509 AddPrincipalListEntry(IN PSECURITY_PAGE sp,
510 IN PPRINCIPAL_LISTITEM PrincipalListItem,
511 IN INT Index,
512 IN BOOL Selected)
513 {
514 LVITEM li;
515
516 li.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
517 li.iItem = Index;
518 li.iSubItem = 0;
519 li.state = (Selected ? LVIS_SELECTED : 0);
520 li.stateMask = LVIS_SELECTED;
521 li.pszText = (PrincipalListItem->DisplayString != NULL ?
522 PrincipalListItem->DisplayString :
523 PrincipalListItem->AccountName);
524
525 switch (PrincipalListItem->SidNameUse)
526 {
527 case SidTypeUser:
528 li.iImage = 0;
529 break;
530 case SidTypeGroup:
531 li.iImage = 1;
532 break;
533 default:
534 li.iImage = -1;
535 break;
536 }
537 li.lParam = (LPARAM)PrincipalListItem;
538
539 return ListView_InsertItem(sp->hWndPrincipalsList,
540 &li);
541 }
542
543 static VOID
544 FillPrincipalsList(IN PSECURITY_PAGE sp)
545 {
546 LPARAM SelLParam;
547 PPRINCIPAL_LISTITEM CurItem;
548 RECT rcLvClient;
549
550 SelLParam = ListViewGetSelectedItemData(sp->hWndPrincipalsList);
551
552 DisableRedrawWindow(sp->hWndPrincipalsList);
553
554 ListView_DeleteAllItems(sp->hWndPrincipalsList);
555
556 for (CurItem = sp->PrincipalsListHead;
557 CurItem != NULL;
558 CurItem = CurItem->Next)
559 {
560 AddPrincipalListEntry(sp,
561 CurItem,
562 -1,
563 (SelLParam == (LPARAM)CurItem));
564 }
565
566 EnableRedrawWindow(sp->hWndPrincipalsList);
567
568 GetClientRect(sp->hWndPrincipalsList,
569 &rcLvClient);
570
571 ListView_SetColumnWidth(sp->hWndPrincipalsList,
572 0,
573 rcLvClient.right);
574 }
575
576 static VOID
577 UpdateControlStates(IN PSECURITY_PAGE sp)
578 {
579 PPRINCIPAL_LISTITEM Selected = (PPRINCIPAL_LISTITEM)ListViewGetSelectedItemData(sp->hWndPrincipalsList);
580
581 EnableWindow(sp->hBtnRemove,
582 Selected != NULL);
583 EnableWindow(sp->hAceCheckList,
584 Selected != NULL);
585
586 if (Selected != NULL)
587 {
588 LPWSTR szLabel;
589
590 if (LoadAndFormatString(hDllInstance,
591 IDS_PERMISSIONS_FOR,
592 &szLabel,
593 Selected->AccountName))
594 {
595 SetWindowText(sp->hPermissionsForLabel,
596 szLabel);
597
598 LocalFree((HLOCAL)szLabel);
599 }
600
601 /* FIXME - update the checkboxes */
602 }
603 else
604 {
605 WCHAR szPermissions[255];
606
607 if (LoadString(hDllInstance,
608 IDS_PERMISSIONS,
609 szPermissions,
610 sizeof(szPermissions) / sizeof(szPermissions[0])))
611 {
612 SetWindowText(sp->hPermissionsForLabel,
613 szPermissions);
614 }
615
616 SendMessage(sp->hAceCheckList,
617 CLM_CLEARCHECKBOXES,
618 0,
619 0);
620 }
621 }
622
623 static UINT CALLBACK
624 SecurityPageCallback(IN HWND hwnd,
625 IN UINT uMsg,
626 IN LPPROPSHEETPAGE ppsp)
627 {
628 PSECURITY_PAGE sp = (PSECURITY_PAGE)ppsp->lParam;
629
630 switch (uMsg)
631 {
632 case PSPCB_CREATE:
633 {
634 return TRUE;
635 }
636 case PSPCB_RELEASE:
637 {
638 DestroySecurityPage(sp);
639 return FALSE;
640 }
641 }
642
643 return FALSE;
644 }
645
646 static VOID
647 SetAceCheckListColumns(IN HWND hAceCheckList,
648 IN UINT Button,
649 IN HWND hLabel)
650 {
651 POINT pt;
652 RECT rcLabel;
653
654 GetWindowRect(hLabel,
655 &rcLabel);
656 pt.y = 0;
657 pt.x = (rcLabel.right - rcLabel.left) / 2;
658 MapWindowPoints(hLabel,
659 hAceCheckList,
660 &pt,
661 1);
662
663 SendMessage(hAceCheckList,
664 CLM_SETCHECKBOXCOLUMN,
665 Button,
666 pt.x);
667 }
668
669 static VOID
670 LoadPermissionsList(IN PSECURITY_PAGE sp,
671 IN GUID *GuidObjectType,
672 IN DWORD dwFlags,
673 OUT SI_ACCESS *DefaultAccess)
674 {
675 HRESULT hRet;
676 PSI_ACCESS AccessList;
677 ULONG nAccessList, DefaultAccessIndex;
678 WCHAR szSpecialPermissions[255];
679 BOOLEAN SpecialPermissionsPresent = FALSE;
680 ACCESS_MASK SpecialPermissionsMask = 0;
681
682 /* clear the permissions list */
683
684 SendMessage(sp->hAceCheckList,
685 CLM_CLEAR,
686 0,
687 0);
688
689 /* query the access rights from the server */
690 hRet = sp->psi->lpVtbl->GetAccessRights(sp->psi,
691 GuidObjectType,
692 dwFlags, /* FIXME */
693 &AccessList,
694 &nAccessList,
695 &DefaultAccessIndex);
696 if (SUCCEEDED(hRet) && nAccessList != 0)
697 {
698 LPCWSTR NameStr;
699 PSI_ACCESS CurAccess, LastAccess;
700 WCHAR NameBuffer[MAX_PATH];
701
702 /* save the default access rights to be used when adding ACEs later */
703 if (DefaultAccess != NULL)
704 {
705 *DefaultAccess = AccessList[DefaultAccessIndex];
706 }
707
708 LastAccess = AccessList + nAccessList;
709 for (CurAccess = &AccessList[0];
710 CurAccess != LastAccess;
711 CurAccess++)
712 {
713 if (CurAccess->dwFlags & dwFlags)
714 {
715 /* get the permission name, load it from a string table if necessary */
716 if (IS_INTRESOURCE(CurAccess->pszName))
717 {
718 if (!LoadString(sp->ObjectInfo.hInstance,
719 (UINT)((ULONG_PTR)CurAccess->pszName),
720 NameBuffer,
721 sizeof(NameBuffer) / sizeof(NameBuffer[0])))
722 {
723 LoadString(hDllInstance,
724 IDS_UNKNOWN,
725 NameBuffer,
726 sizeof(NameBuffer) / sizeof(NameBuffer[0]));
727 }
728 NameStr = NameBuffer;
729 }
730 else
731 {
732 NameStr = CurAccess->pszName;
733 }
734
735 SendMessage(sp->hAceCheckList,
736 CLM_ADDITEM,
737 (WPARAM)CurAccess->mask,
738 (LPARAM)NameStr);
739 }
740 else if (CurAccess->dwFlags & SI_ACCESS_SPECIFIC)
741 {
742 SpecialPermissionsPresent = TRUE;
743 SpecialPermissionsMask |= CurAccess->mask;
744 }
745 }
746 }
747
748 /* add the special permissions check item in case the specific access rights
749 aren't displayed */
750 if (SpecialPermissionsPresent &&
751 LoadString(hDllInstance,
752 IDS_SPECIAL_PERMISSIONS,
753 szSpecialPermissions,
754 sizeof(szSpecialPermissions) / sizeof(szSpecialPermissions[0])))
755 {
756 /* add the special permissions check item */
757 sp->SpecialPermCheckIndex = (INT)SendMessage(sp->hAceCheckList,
758 CLM_ADDITEM,
759 (WPARAM)SpecialPermissionsMask,
760 (LPARAM)szSpecialPermissions);
761 if (sp->SpecialPermCheckIndex != -1)
762 {
763 SendMessage(sp->hAceCheckList,
764 CLM_SETITEMSTATE,
765 (WPARAM)sp->SpecialPermCheckIndex,
766 CIS_ALLOWDISABLED | CIS_DENYDISABLED | CIS_NONE);
767 }
768 }
769 }
770
771 static VOID
772 ResizeControls(IN PSECURITY_PAGE sp,
773 IN INT Width,
774 IN INT Height)
775 {
776 HWND hWndAllow, hWndDeny;
777 RECT rcControl, rcControl2, rcControl3, rcWnd;
778 INT cxWidth, cxEdge, btnSpacing;
779 POINT pt, pt2;
780 HDWP dwp;
781 INT nControls = 7;
782 LVCOLUMN lvc;
783
784 hWndAllow = GetDlgItem(sp->hWnd,
785 IDC_LABEL_ALLOW);
786 hWndDeny = GetDlgItem(sp->hWnd,
787 IDC_LABEL_DENY);
788
789 GetWindowRect(sp->hWnd,
790 &rcWnd);
791
792 cxEdge = GetSystemMetrics(SM_CXEDGE);
793
794 /* use the left margin of the principal list view control for all control
795 margins */
796 pt.x = 0;
797 pt.y = 0;
798 MapWindowPoints(sp->hWndPrincipalsList,
799 sp->hWnd,
800 &pt,
801 1);
802 cxWidth = Width - (2 * pt.x);
803
804 if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
805 {
806 nControls += 2;
807 }
808
809 if ((dwp = BeginDeferWindowPos(nControls)))
810 {
811 /* resize the Principal list view */
812 GetWindowRect(sp->hWndPrincipalsList,
813 &rcControl);
814 if (!(dwp = DeferWindowPos(dwp,
815 sp->hWndPrincipalsList,
816 NULL,
817 0,
818 0,
819 cxWidth,
820 rcControl.bottom - rcControl.top,
821 SWP_NOMOVE | SWP_NOZORDER)))
822 {
823 goto EndDeferWnds;
824 }
825
826 /* move the Add Principal button */
827 GetWindowRect(sp->hBtnAdd,
828 &rcControl);
829 GetWindowRect(sp->hBtnRemove,
830 &rcControl2);
831 btnSpacing = rcControl2.left - rcControl.right;
832 pt2.x = 0;
833 pt2.y = 0;
834 MapWindowPoints(sp->hBtnAdd,
835 sp->hWnd,
836 &pt2,
837 1);
838 if (!(dwp = DeferWindowPos(dwp,
839 sp->hBtnAdd,
840 NULL,
841 pt.x + cxWidth - (rcControl2.right - rcControl2.left) -
842 (rcControl.right - rcControl.left) -
843 btnSpacing - cxEdge,
844 pt2.y,
845 0,
846 0,
847 SWP_NOSIZE | SWP_NOZORDER)))
848 {
849 goto EndDeferWnds;
850 }
851
852 /* move the Delete Principal button */
853 pt2.x = 0;
854 pt2.y = 0;
855 MapWindowPoints(sp->hBtnRemove,
856 sp->hWnd,
857 &pt2,
858 1);
859 if (!(dwp = DeferWindowPos(dwp,
860 sp->hBtnRemove,
861 NULL,
862 pt.x + cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
863 pt2.y,
864 0,
865 0,
866 SWP_NOSIZE | SWP_NOZORDER)))
867 {
868 goto EndDeferWnds;
869 }
870
871 /* move the Permissions For label */
872 GetWindowRect(hWndAllow,
873 &rcControl);
874 GetWindowRect(hWndDeny,
875 &rcControl2);
876 GetWindowRect(sp->hPermissionsForLabel,
877 &rcControl3);
878 pt2.x = 0;
879 pt2.y = 0;
880 MapWindowPoints(sp->hPermissionsForLabel,
881 sp->hWnd,
882 &pt2,
883 1);
884 if (!(dwp = DeferWindowPos(dwp,
885 sp->hPermissionsForLabel,
886 NULL,
887 0,
888 0,
889 cxWidth - (rcControl2.right - rcControl2.left) -
890 (rcControl.right - rcControl.left) -
891 (2 * btnSpacing) - cxEdge,
892 rcControl3.bottom - rcControl3.top,
893 SWP_NOMOVE | SWP_NOZORDER)))
894 {
895 goto EndDeferWnds;
896 }
897
898 /* move the Allow label */
899 pt2.x = 0;
900 pt2.y = 0;
901 MapWindowPoints(hWndAllow,
902 sp->hWnd,
903 &pt2,
904 1);
905 if (!(dwp = DeferWindowPos(dwp,
906 hWndAllow,
907 NULL,
908 cxWidth - (rcControl2.right - rcControl2.left) -
909 (rcControl.right - rcControl.left) -
910 btnSpacing - cxEdge,
911 pt2.y,
912 0,
913 0,
914 SWP_NOSIZE | SWP_NOZORDER)))
915 {
916 goto EndDeferWnds;
917 }
918
919 /* move the Deny label */
920 pt2.x = 0;
921 pt2.y = 0;
922 MapWindowPoints(hWndDeny,
923 sp->hWnd,
924 &pt2,
925 1);
926 if (!(dwp = DeferWindowPos(dwp,
927 hWndDeny,
928 NULL,
929 cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
930 pt2.y,
931 0,
932 0,
933 SWP_NOSIZE | SWP_NOZORDER)))
934 {
935 goto EndDeferWnds;
936 }
937
938 /* resize the Permissions check list box */
939 GetWindowRect(sp->hAceCheckList,
940 &rcControl);
941 GetWindowRect(sp->hBtnAdvanced,
942 &rcControl2);
943 GetWindowRect(GetDlgItem(sp->hWnd,
944 IDC_LABEL_ADVANCED),
945 &rcControl3);
946 if (!(dwp = DeferWindowPos(dwp,
947 sp->hAceCheckList,
948 NULL,
949 0,
950 0,
951 cxWidth,
952 ((sp->ObjectInfo.dwFlags & SI_ADVANCED) ?
953 Height - (rcControl.top - rcWnd.top) -
954 (rcControl3.bottom - rcControl3.top) - pt.x - btnSpacing :
955 Height - (rcControl.top - rcWnd.top) - pt.x),
956 SWP_NOMOVE | SWP_NOZORDER)))
957 {
958 goto EndDeferWnds;
959 }
960
961 if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
962 {
963 /* move and resize the Advanced label */
964 if (!(dwp = DeferWindowPos(dwp,
965 GetDlgItem(sp->hWnd,
966 IDC_LABEL_ADVANCED),
967 NULL,
968 pt.x,
969 Height - (rcControl3.bottom - rcControl3.top) - pt.x,
970 cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
971 rcControl3.bottom - rcControl3.top,
972 SWP_NOZORDER)))
973 {
974 goto EndDeferWnds;
975 }
976
977 /* move and resize the Advanced button */
978 if (!(dwp = DeferWindowPos(dwp,
979 sp->hBtnAdvanced,
980 NULL,
981 cxWidth - (rcControl2.right - rcControl2.left) + pt.x,
982 Height - (rcControl2.bottom - rcControl2.top) - pt.x,
983 0,
984 0,
985 SWP_NOSIZE | SWP_NOZORDER)))
986 {
987 goto EndDeferWnds;
988 }
989 }
990
991 EndDeferWindowPos(dwp);
992 }
993
994 EndDeferWnds:
995 /* update the width of the principal list view column */
996 GetClientRect(sp->hWndPrincipalsList,
997 &rcControl);
998 lvc.mask = LVCF_WIDTH;
999 lvc.cx = rcControl.right;
1000 ListView_SetColumn(sp->hWndPrincipalsList,
1001 0,
1002 &lvc);
1003
1004 /* calculate the columns of the allow/deny checkboxes */
1005 SetAceCheckListColumns(sp->hAceCheckList,
1006 CLB_ALLOW,
1007 hWndAllow);
1008 SetAceCheckListColumns(sp->hAceCheckList,
1009 CLB_DENY,
1010 hWndDeny);
1011 }
1012
1013 static PACE_HEADER
1014 BuildDefaultPrincipalAce(IN PSECURITY_PAGE sp,
1015 IN PSID pSid)
1016 {
1017 PACCESS_ALLOWED_ACE Ace;
1018 DWORD SidLen;
1019 WORD AceSize;
1020
1021 SidLen = GetLengthSid(pSid);
1022 AceSize = sizeof(ACCESS_ALLOWED_ACE) + (WORD)SidLen - sizeof(DWORD);
1023 Ace = HeapAlloc(GetProcessHeap(),
1024 0,
1025 AceSize);
1026 if (Ace != NULL)
1027 {
1028 Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
1029 Ace->Header.AceFlags = 0; /* FIXME */
1030 Ace->Header.AceSize = AceSize;
1031 Ace->Mask = sp->DefaultAccess.mask;
1032
1033 if (CopySid(SidLen,
1034 (PSID)&Ace->SidStart,
1035 pSid))
1036 {
1037 return &Ace->Header;
1038 }
1039
1040 HeapFree(GetProcessHeap(),
1041 0,
1042 Ace);
1043 }
1044
1045 return NULL;
1046 }
1047
1048 static BOOL
1049 AddSelectedPrincipal(IN IDsObjectPicker *pDsObjectPicker,
1050 IN HWND hwndParent OPTIONAL,
1051 IN PSID pSid,
1052 IN PVOID Context OPTIONAL)
1053 {
1054 PACE_HEADER AceHeader;
1055 PSECURITY_PAGE sp = (PSECURITY_PAGE)Context;
1056
1057 AceHeader = BuildDefaultPrincipalAce(sp,
1058 pSid);
1059 if (AceHeader != NULL)
1060 {
1061 AddPrincipalToList(sp,
1062 pSid,
1063 AceHeader);
1064
1065 HeapFree(GetProcessHeap(),
1066 0,
1067 AceHeader);
1068 }
1069
1070 return TRUE;
1071 }
1072
1073 static INT_PTR CALLBACK
1074 SecurityPageProc(IN HWND hwndDlg,
1075 IN UINT uMsg,
1076 IN WPARAM wParam,
1077 IN LPARAM lParam)
1078 {
1079 PSECURITY_PAGE sp;
1080 INT_PTR Ret = FALSE;
1081
1082 sp = (PSECURITY_PAGE)GetWindowLongPtr(hwndDlg,
1083 DWL_USER);
1084 if (sp != NULL || uMsg == WM_INITDIALOG)
1085 {
1086 switch (uMsg)
1087 {
1088 case WM_NOTIFY:
1089 {
1090 NMHDR *pnmh = (NMHDR*)lParam;
1091
1092 if (pnmh->hwndFrom == sp->hWndPrincipalsList)
1093 {
1094 switch (pnmh->code)
1095 {
1096 case LVN_ITEMCHANGED:
1097 {
1098 LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
1099
1100 if ((pnmv->uChanged & LVIF_STATE) &&
1101 ((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) ||
1102 (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))))
1103 {
1104 UpdateControlStates(sp);
1105 }
1106 break;
1107 }
1108 }
1109 }
1110 else if (pnmh->hwndFrom == sp->hAceCheckList)
1111 {
1112 switch (pnmh->code)
1113 {
1114 case CLN_CHANGINGITEMCHECKBOX:
1115 {
1116 PNMCHANGEITEMCHECKBOX pcicb = (PNMCHANGEITEMCHECKBOX)lParam;
1117
1118 /* make sure only one of both checkboxes is only checked
1119 at the same time */
1120 if (pcicb->Checked)
1121 {
1122 pcicb->NewState &= ~((pcicb->CheckBox != CLB_DENY) ? CIS_DENY : CIS_ALLOW);
1123 }
1124 break;
1125 }
1126 }
1127 }
1128 break;
1129 }
1130
1131 case WM_COMMAND:
1132 {
1133 switch (LOWORD(wParam))
1134 {
1135 case IDC_ADD_PRINCIPAL:
1136 {
1137 HRESULT hRet;
1138
1139 hRet = InitializeObjectPicker(sp->ServerName,
1140 &sp->ObjectInfo,
1141 &sp->pDsObjectPicker);
1142 if (SUCCEEDED(hRet))
1143 {
1144 hRet = InvokeObjectPickerDialog(sp->pDsObjectPicker,
1145 hwndDlg,
1146 AddSelectedPrincipal,
1147 sp);
1148 if (FAILED(hRet))
1149 {
1150 MessageBox(hwndDlg, L"InvokeObjectPickerDialog failed!\n", NULL, 0);
1151 }
1152
1153 /* delete the instance */
1154 FreeObjectPicker(sp->pDsObjectPicker);
1155
1156 /* reload the principal list */
1157 FillPrincipalsList(sp);
1158 }
1159 else
1160 {
1161 MessageBox(hwndDlg, L"InitializeObjectPicker failed!\n", NULL, 0);
1162 }
1163 break;
1164 }
1165
1166 case IDC_REMOVE_PRINCIPAL:
1167 {
1168 PPRINCIPAL_LISTITEM SelectedPrincipal;
1169
1170 SelectedPrincipal = (PPRINCIPAL_LISTITEM)ListViewGetSelectedItemData(sp->hWndPrincipalsList);
1171 if (SelectedPrincipal != NULL)
1172 {
1173 /* FIXME */
1174 }
1175 break;
1176 }
1177 }
1178 break;
1179 }
1180
1181 case WM_SIZE:
1182 {
1183 ResizeControls(sp,
1184 (INT)LOWORD(lParam),
1185 (INT)HIWORD(lParam));
1186 break;
1187 }
1188
1189 case WM_INITDIALOG:
1190 {
1191 sp = (PSECURITY_PAGE)((LPPROPSHEETPAGE)lParam)->lParam;
1192 if(sp != NULL)
1193 {
1194 LV_COLUMN lvc;
1195 RECT rcLvClient;
1196
1197 sp->hWnd = hwndDlg;
1198 sp->hWndPrincipalsList = GetDlgItem(hwndDlg, IDC_PRINCIPALS);
1199 sp->hBtnAdd = GetDlgItem(hwndDlg, IDC_ADD_PRINCIPAL);
1200 sp->hBtnRemove = GetDlgItem(hwndDlg, IDC_REMOVE_PRINCIPAL);
1201 sp->hBtnAdvanced = GetDlgItem(hwndDlg, IDC_ADVANCED);
1202 sp->hAceCheckList = GetDlgItem(hwndDlg, IDC_ACE_CHECKLIST);
1203 sp->hPermissionsForLabel = GetDlgItem(hwndDlg, IDC_LABEL_PERMISSIONS_FOR);
1204
1205 sp->SpecialPermCheckIndex = -1;
1206
1207 if ((sp->ObjectInfo.dwFlags & SI_SERVER_IS_DC) &&
1208 sp->ObjectInfo.pszServerName != NULL &&
1209 sp->ObjectInfo.pszServerName[0] != L'\0')
1210 {
1211 sp->ServerName = sp->ObjectInfo.pszServerName;
1212 }
1213
1214 /* save the pointer to the structure */
1215 SetWindowLongPtr(hwndDlg,
1216 DWL_USER,
1217 (DWORD_PTR)sp);
1218
1219 ListView_SetExtendedListViewStyleEx(sp->hWndPrincipalsList,
1220 LVS_EX_FULLROWSELECT,
1221 LVS_EX_FULLROWSELECT);
1222
1223 sp->hiPrincipals = ImageList_LoadBitmap(hDllInstance,
1224 MAKEINTRESOURCE(IDB_USRGRPIMAGES),
1225 16,
1226 3,
1227 RGB(255,
1228 0,
1229 255));
1230
1231 /* setup the listview control */
1232 if (sp->hiPrincipals != NULL)
1233 {
1234 ListView_SetImageList(sp->hWndPrincipalsList,
1235 sp->hiPrincipals,
1236 LVSIL_SMALL);
1237 }
1238
1239 GetClientRect(sp->hWndPrincipalsList,
1240 &rcLvClient);
1241
1242 /* add a column to the list view */
1243 lvc.mask = LVCF_FMT | LVCF_WIDTH;
1244 lvc.fmt = LVCFMT_LEFT;
1245 lvc.cx = rcLvClient.right;
1246 ListView_InsertColumn(sp->hWndPrincipalsList,
1247 0,
1248 &lvc);
1249
1250 ReloadPrincipalsList(sp);
1251
1252 FillPrincipalsList(sp);
1253
1254 ListViewSelectItem(sp->hWndPrincipalsList,
1255 0);
1256
1257 /* calculate the columns of the allow/deny checkboxes */
1258 SetAceCheckListColumns(sp->hAceCheckList,
1259 CLB_ALLOW,
1260 GetDlgItem(hwndDlg, IDC_LABEL_ALLOW));
1261 SetAceCheckListColumns(sp->hAceCheckList,
1262 CLB_DENY,
1263 GetDlgItem(hwndDlg, IDC_LABEL_DENY));
1264
1265 LoadPermissionsList(sp,
1266 NULL,
1267 SI_ACCESS_GENERAL |
1268 ((sp->ObjectInfo.dwFlags & SI_CONTAINER) ? SI_ACCESS_CONTAINER : 0),
1269 &sp->DefaultAccess);
1270
1271 /* hide controls in case the flags aren't present */
1272 if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
1273 {
1274 /* editing the permissions is least the user can do when
1275 the advanced button is showed */
1276 sp->ObjectInfo.dwFlags |= SI_EDIT_PERMS;
1277 }
1278 else
1279 {
1280 ShowWindow(sp->hBtnAdvanced,
1281 SW_HIDE);
1282 ShowWindow(GetDlgItem(hwndDlg, IDC_LABEL_ADVANCED),
1283 SW_HIDE);
1284 }
1285
1286 /* enable quicksearch for the permissions checklist control */
1287 SendMessage(sp->hAceCheckList,
1288 CLM_ENABLEQUICKSEARCH,
1289 TRUE,
1290 0);
1291
1292 UpdateControlStates(sp);
1293 }
1294
1295 Ret = TRUE;
1296 break;
1297 }
1298 }
1299 }
1300 return Ret;
1301 }
1302
1303
1304 /*
1305 * CreateSecurityPage EXPORTED
1306 *
1307 * @implemented
1308 */
1309 HPROPSHEETPAGE
1310 WINAPI
1311 CreateSecurityPage(IN LPSECURITYINFO psi)
1312 {
1313 PROPSHEETPAGE psp = {0};
1314 PSECURITY_PAGE sPage;
1315 SI_OBJECT_INFO ObjectInfo = {0};
1316 HRESULT hRet;
1317
1318 if (psi == NULL)
1319 {
1320 SetLastError(ERROR_INVALID_PARAMETER);
1321
1322 DPRINT("No ISecurityInformation class passed!\n");
1323 return NULL;
1324 }
1325
1326 /* get the object information from the server. Zero the structure before
1327 because some applications seem to return SUCCESS but only seem to set the
1328 fields they care about. */
1329 hRet = psi->lpVtbl->GetObjectInformation(psi,
1330 &ObjectInfo);
1331
1332 if (FAILED(hRet))
1333 {
1334 SetLastError(hRet);
1335
1336 DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n");
1337 return NULL;
1338 }
1339
1340 hRet = CoInitialize(NULL);
1341 if (FAILED(hRet))
1342 {
1343 DPRINT("CoInitialize failed!\n");
1344 return NULL;
1345 }
1346
1347 sPage = HeapAlloc(GetProcessHeap(),
1348 HEAP_ZERO_MEMORY,
1349 sizeof(SECURITY_PAGE));
1350 if (sPage == NULL)
1351 {
1352 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1353
1354 DPRINT("Not enough memory to allocate a SECURITY_PAGE!\n");
1355 return NULL;
1356 }
1357 sPage->psi = psi;
1358 sPage->ObjectInfo = ObjectInfo;
1359
1360 psp.dwSize = sizeof(PROPSHEETPAGE);
1361 psp.dwFlags = PSP_USECALLBACK;
1362 psp.hInstance = hDllInstance;
1363 psp.pszTemplate = MAKEINTRESOURCE(IDD_SECPAGE);
1364 psp.pfnDlgProc = SecurityPageProc;
1365 psp.lParam = (LPARAM)sPage;
1366 psp.pfnCallback = SecurityPageCallback;
1367
1368 if (ObjectInfo.dwFlags & SI_PAGE_TITLE)
1369 {
1370 psp.pszTitle = ObjectInfo.pszPageTitle;
1371
1372 if (psp.pszTitle != NULL)
1373 {
1374 psp.dwFlags |= PSP_USETITLE;
1375 }
1376 }
1377 else
1378 {
1379 psp.pszTitle = NULL;
1380 }
1381
1382 /* NOTE: the SECURITY_PAGE structure will be freed by the property page
1383 callback! */
1384
1385 return CreatePropertySheetPage(&psp);
1386 }
1387
1388
1389 /*
1390 * EditSecurity EXPORTED
1391 *
1392 * @implemented
1393 */
1394 BOOL
1395 WINAPI
1396 EditSecurity(IN HWND hwndOwner,
1397 IN LPSECURITYINFO psi)
1398 {
1399 HRESULT hRet;
1400 SI_OBJECT_INFO ObjectInfo = {0};
1401 PROPSHEETHEADER psh;
1402 HPROPSHEETPAGE hPages[1];
1403 LPWSTR lpCaption = NULL;
1404 BOOL Ret;
1405
1406 if (psi == NULL)
1407 {
1408 SetLastError(ERROR_INVALID_PARAMETER);
1409
1410 DPRINT("No ISecurityInformation class passed!\n");
1411 return FALSE;
1412 }
1413
1414 /* get the object information from the server. Zero the structure before
1415 because some applications seem to return SUCCESS but only seem to set the
1416 fields they care about. */
1417 hRet = psi->lpVtbl->GetObjectInformation(psi,
1418 &ObjectInfo);
1419
1420 if (FAILED(hRet))
1421 {
1422 SetLastError(hRet);
1423
1424 DPRINT("GetObjectInformation() failed!\n");
1425 return FALSE;
1426 }
1427
1428 /* create the page */
1429 hPages[0] = CreateSecurityPage(psi);
1430 if (hPages[0] == NULL)
1431 {
1432 DPRINT("CreateSecurityPage(), couldn't create property sheet!\n");
1433 return FALSE;
1434 }
1435
1436 psh.dwSize = sizeof(PROPSHEETHEADER);
1437 psh.dwFlags = PSH_DEFAULT;
1438 psh.hwndParent = hwndOwner;
1439 psh.hInstance = hDllInstance;
1440
1441 /* Set the page title to the object name, make sure the format string
1442 has "%1" NOT "%s" because it uses FormatMessage() to automatically
1443 allocate the right amount of memory. */
1444 if (LoadAndFormatString(hDllInstance,
1445 IDS_PSP_TITLE,
1446 &lpCaption,
1447 ObjectInfo.pszObjectName))
1448 {
1449 psh.pszCaption = lpCaption;
1450 }
1451 else
1452 {
1453 psh.pszCaption = ObjectInfo.pszObjectName;
1454 }
1455
1456 psh.nPages = sizeof(hPages) / sizeof(HPROPSHEETPAGE);
1457 psh.nStartPage = 0;
1458 psh.phpage = hPages;
1459
1460 Ret = (PropertySheet(&psh) != -1);
1461
1462 if (lpCaption != NULL)
1463 {
1464 LocalFree((HLOCAL)lpCaption);
1465 }
1466
1467 return Ret;
1468 }
1469
1470 BOOL
1471 WINAPI
1472 DllMain(IN HINSTANCE hinstDLL,
1473 IN DWORD dwReason,
1474 IN LPVOID lpvReserved)
1475 {
1476 switch (dwReason)
1477 {
1478 case DLL_PROCESS_ATTACH:
1479 hDllInstance = hinstDLL;
1480
1481 DisableThreadLibraryCalls(hinstDLL);
1482
1483 if (!RegisterCheckListControl(hinstDLL))
1484 {
1485 DPRINT("Registering the CHECKLIST_ACLUI class failed!\n");
1486 return FALSE;
1487 }
1488 break;
1489
1490 case DLL_PROCESS_DETACH:
1491 UnregisterCheckListControl();
1492 break;
1493 }
1494
1495 return TRUE;
1496 }
1497