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