2 * Implementation of the AclUI
4 * Copyright (C) 2009 Nikolay Sivov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(aclui
);
35 /* the aclui.h files does not contain the necessary COBJMACROS */
36 #define ISecurityInformation_AddRef(This) (This)->lpVtbl->AddRef(This)
37 #define ISecurityInformation_Release(This) (This)->lpVtbl->Release(This)
38 #define ISecurityInformation_GetObjectInformation(This, obj) (This)->lpVtbl->GetObjectInformation(This, obj)
39 #define ISecurityInformation_GetSecurity(This, info, sd, def) (This)->lpVtbl->GetSecurity(This, info, sd, def)
40 #define ISecurityInformation_GetAccessRights(This, type, flags, access, count, def) (This)->lpVtbl->GetAccessRights(This, type, flags, access, count, def)
50 ISecurityInformation
*security
;
52 PSECURITY_DESCRIPTOR sd
;
58 unsigned int user_count
;
61 HIMAGELIST image_list
;
64 static HINSTANCE aclui_instance
;
66 static WCHAR
*WINAPIV
load_formatstr(UINT resource
, ...)
72 va_start(valist
, resource
);
73 ret
= FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_HMODULE
,
74 aclui_instance
, resource
, 0, (WCHAR
*)&str
, 0, &valist
);
76 return ret
? str
: NULL
;
79 static WCHAR
*get_sid_name(PSID sid
, SID_NAME_USE
*sid_type
)
86 LookupAccountSidW(NULL
, sid
, NULL
, &name_len
, NULL
, &domain_len
, sid_type
);
87 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
89 if (!(name
= malloc(name_len
* sizeof(WCHAR
))))
91 if (!(domain
= malloc(domain_len
* sizeof(WCHAR
))))
97 ret
= LookupAccountSidW(NULL
, sid
, name
, &name_len
, domain
, &domain_len
, sid_type
);
104 static void add_user(struct security_page
*page
, PSID sid
)
106 struct user
*new_array
, *user
;
107 SID_NAME_USE sid_type
;
112 /* check if we already processed this user or group */
113 for (i
= 0; i
< page
->user_count
; ++i
)
115 if (EqualSid(sid
, page
->users
[i
].sid
))
119 if (!(name
= get_sid_name(sid
, &sid_type
)))
122 if (!(new_array
= realloc(page
->users
, (page
->user_count
+ 1) * sizeof(*page
->users
))))
127 page
->users
= new_array
;
128 user
= &page
->users
[page
->user_count
++];
133 item
.mask
= LVIF_PARAM
| LVIF_TEXT
| LVIF_IMAGE
;
137 item
.lParam
= (LPARAM
)user
;
138 item
.iImage
= (sid_type
== SidTypeGroup
|| sid_type
== SidTypeWellKnownGroup
) ? 0 : 1;
140 SendMessageW(GetDlgItem(page
->dialog
, IDC_USERS
), LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
143 static PSID
get_sid_from_ace(ACE_HEADER
*ace
)
145 switch (ace
->AceType
)
147 case ACCESS_ALLOWED_ACE_TYPE
:
148 return &((ACCESS_ALLOWED_ACE
*)ace
)->SidStart
;
149 case ACCESS_DENIED_ACE_TYPE
:
150 return &((ACCESS_DENIED_ACE
*)ace
)->SidStart
;
152 FIXME("Unhandled ACE type %#x.\n", ace
->AceType
);
157 static void compute_access_masks(PSECURITY_DESCRIPTOR sd
, PSID sid
, ACCESS_MASK
*allowed
, ACCESS_MASK
*denied
)
159 BOOL defaulted
, present
;
168 if (!GetSecurityDescriptorDacl(sd
, &present
, &dacl
, &defaulted
) || !present
)
171 for (index
= 0; index
< dacl
->AceCount
; index
++)
173 if (!GetAce(dacl
, index
, (void**)&ace
))
176 ace_sid
= get_sid_from_ace(ace
);
177 if (!ace_sid
|| !EqualSid(ace_sid
, sid
))
180 if (ace
->AceType
== ACCESS_ALLOWED_ACE_TYPE
)
181 *allowed
|= ((ACCESS_ALLOWED_ACE
*)ace
)->Mask
;
182 else if (ace
->AceType
== ACCESS_DENIED_ACE_TYPE
)
183 *denied
|= ((ACCESS_DENIED_ACE
*)ace
)->Mask
;
187 static void update_access_list(struct security_page
*page
, struct user
*user
)
189 ACCESS_MASK allowed
, denied
;
195 compute_access_masks(page
->sd
, user
->sid
, &allowed
, &denied
);
197 if ((infotext
= load_formatstr(IDS_PERMISSION_FOR
, user
->name
)))
199 SetDlgItemTextW(page
->dialog
, IDC_ACE_USER
, infotext
);
203 control
= GetDlgItem(page
->dialog
, IDC_ACE
);
205 for (i
= 0; i
< page
->access_count
; i
++)
207 if (!(page
->access
[i
].dwFlags
& SI_ACCESS_GENERAL
))
210 item
.mask
= LVIF_TEXT
;
214 if ((page
->access
[i
].mask
& allowed
) == page
->access
[i
].mask
)
215 item
.pszText
= (WCHAR
*)L
"X";
217 item
.pszText
= (WCHAR
*)L
"-";
218 SendMessageW(control
, LVM_SETITEMW
, 0, (LPARAM
)&item
);
221 if ((page
->access
[i
].mask
& denied
) == page
->access
[i
].mask
)
222 item
.pszText
= (WCHAR
*)L
"X";
224 item
.pszText
= (WCHAR
*)L
"-";
225 SendMessageW(control
, LVM_SETITEMW
, 0, (LPARAM
)&item
);
231 static void init_users(struct security_page
*page
)
233 BOOL defaulted
, present
;
239 if (!GetSecurityDescriptorDacl(page
->sd
, &present
, &dacl
, &defaulted
))
241 ERR("Failed to query descriptor information, error %lu.\n", GetLastError());
248 for (index
= 0; index
< dacl
->AceCount
; index
++)
250 if (!GetAce(dacl
, index
, (void **)&ace
))
252 if (!(sid
= get_sid_from_ace(ace
)))
258 static void init_access_list(struct security_page
*page
)
265 control
= GetDlgItem(page
->dialog
, IDC_ACE
);
267 for (i
= 0; i
< page
->access_count
; i
++)
269 if (!(page
->access
[i
].dwFlags
& SI_ACCESS_GENERAL
))
272 item
.mask
= LVIF_TEXT
;
275 if (IS_INTRESOURCE(page
->access
[i
].pszName
))
278 LoadStringW(page
->info
.hInstance
, (DWORD_PTR
)page
->access
[i
].pszName
, str
, ARRAY_SIZE(str
));
282 item
.pszText
= (WCHAR
*)page
->access
[i
].pszName
;
283 SendMessageW(control
, LVM_INSERTITEMW
, 0, (LPARAM
)&item
);
289 static HIMAGELIST
create_image_list(UINT resource
, UINT width
, UINT height
, UINT count
, COLORREF mask_color
)
291 HIMAGELIST image_list
;
295 if (!(image_list
= ImageList_Create(width
, height
, ILC_COLOR32
| ILC_MASK
, 0, count
)))
297 if (!(image
= LoadBitmapW(aclui_instance
, MAKEINTRESOURCEW(resource
))))
299 ImageList_Destroy(image_list
);
303 ret
= ImageList_AddMasked(image_list
, image
, mask_color
);
307 ImageList_Destroy(image_list
);
313 static void security_page_free(struct security_page
*page
)
317 for (i
= 0; i
< page
->user_count
; ++i
)
318 free(page
->users
[i
].name
);
322 if (page
->image_list
)
323 ImageList_Destroy(page
->image_list
);
325 ISecurityInformation_Release(page
->security
);
329 static void security_page_init_dlg(HWND hwnd
, struct security_page
*page
)
339 if (FAILED(hr
= ISecurityInformation_GetSecurity(page
->security
,
340 DACL_SECURITY_INFORMATION
, &page
->sd
, FALSE
)))
342 ERR("Failed to get security descriptor, hr %#lx.\n", hr
);
346 if (FAILED(hr
= ISecurityInformation_GetAccessRights(page
->security
,
347 NULL
, 0, &page
->access
, &page
->access_count
, &def
)))
349 ERR("Failed to get access mapping, hr %#lx.\n", hr
);
355 control
= GetDlgItem(hwnd
, IDC_USERS
);
356 SendMessageW(control
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_FULLROWSELECT
, LVS_EX_FULLROWSELECT
);
358 GetClientRect(control
, &rect
);
359 column
.mask
= LVCF_FMT
| LVCF_WIDTH
;
360 column
.fmt
= LVCFMT_LEFT
;
361 column
.cx
= rect
.right
- rect
.left
;
362 SendMessageW(control
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
364 if (!(page
->image_list
= create_image_list(IDB_USER_ICONS
, 18, 18, 2, RGB(255, 0, 255))))
366 SendMessageW(control
, LVM_SETIMAGELIST
, LVSIL_SMALL
, (LPARAM
)page
->image_list
);
372 control
= GetDlgItem(hwnd
, IDC_ACE
);
373 SendMessageW(control
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_FULLROWSELECT
, LVS_EX_FULLROWSELECT
);
375 column
.mask
= LVCF_FMT
| LVCF_WIDTH
;
376 column
.fmt
= LVCFMT_LEFT
;
378 SendMessageW(control
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&column
);
380 column
.fmt
= LVCFMT_CENTER
;
382 SendMessageW(control
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&column
);
383 SendMessageW(control
, LVM_INSERTCOLUMNW
, 2, (LPARAM
)&column
);
385 init_access_list(page
);
387 if (page
->user_count
)
390 item
.mask
= LVIF_STATE
;
393 item
.state
= LVIS_FOCUSED
| LVIS_SELECTED
;
394 item
.stateMask
= item
.state
;
395 SendMessageW(control
, LVM_SETITEMW
, 0, (LPARAM
)&item
);
399 static INT_PTR CALLBACK
security_page_proc(HWND dialog
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
405 PROPSHEETPAGEW
*propsheet
= (PROPSHEETPAGEW
*)lparam
;
406 SetWindowLongPtrW(dialog
, DWLP_USER
, propsheet
->lParam
);
407 security_page_init_dlg(dialog
, (struct security_page
*)propsheet
->lParam
);
413 struct security_page
*page
= (struct security_page
*)GetWindowLongPtrW(dialog
, DWLP_USER
);
414 NMHDR
*hdr
= (NMHDR
*)lparam
;
416 if (hdr
->hwndFrom
== GetDlgItem(dialog
, IDC_USERS
) && hdr
->code
== LVN_ITEMCHANGED
)
418 NMLISTVIEW
*listview
= (NMLISTVIEW
*)lparam
;
419 if (!(listview
->uOldState
& LVIS_SELECTED
) && (listview
->uNewState
& LVIS_SELECTED
))
420 update_access_list(page
, (struct user
*)listview
->lParam
);
429 static UINT CALLBACK
security_page_callback(HWND hwnd
, UINT msg
, PROPSHEETPAGEW
*ppsp
)
431 struct security_page
*page
= (struct security_page
*)ppsp
->lParam
;
433 if (msg
== PSPCB_RELEASE
)
434 security_page_free(page
);
439 HPROPSHEETPAGE WINAPI
CreateSecurityPage(ISecurityInformation
*security
)
441 struct security_page
*page
;
442 PROPSHEETPAGEW propsheet
;
445 TRACE("%p\n", security
);
447 InitCommonControls();
449 if (!(page
= calloc(1, sizeof(*page
))))
452 if (FAILED(ISecurityInformation_GetObjectInformation(security
, &page
->info
)))
458 page
->security
= security
;
459 ISecurityInformation_AddRef(security
);
461 memset(&propsheet
, 0, sizeof(propsheet
));
462 propsheet
.dwSize
= sizeof(propsheet
);
463 propsheet
.dwFlags
= PSP_DEFAULT
| PSP_USECALLBACK
;
464 propsheet
.hInstance
= aclui_instance
;
465 propsheet
.pszTemplate
= (WCHAR
*)MAKEINTRESOURCE(IDD_SECURITY_PROPERTIES
);
466 propsheet
.pfnDlgProc
= security_page_proc
;
467 propsheet
.pfnCallback
= security_page_callback
;
468 propsheet
.lParam
= (LPARAM
)page
;
470 if (page
->info
.dwFlags
& SI_PAGE_TITLE
)
472 propsheet
.pszTitle
= page
->info
.pszPageTitle
;
473 propsheet
.dwFlags
|= PSP_USETITLE
;
476 if (!(ret
= CreatePropertySheetPageW(&propsheet
)))
478 ERR("Failed to create property sheet page.\n");
479 ISecurityInformation_Release(security
);
486 BOOL WINAPI
EditSecurity(HWND owner
, ISecurityInformation
*security
)
488 PROPSHEETHEADERW sheet
= {0};
489 HPROPSHEETPAGE pages
[1];
493 TRACE("(%p, %p)\n", owner
, security
);
495 if (FAILED(ISecurityInformation_GetObjectInformation(security
, &info
)))
497 if (!(pages
[0] = CreateSecurityPage(security
)))
500 sheet
.dwSize
= sizeof(sheet
);
501 sheet
.dwFlags
= PSH_DEFAULT
;
502 sheet
.hwndParent
= owner
;
503 sheet
.hInstance
= aclui_instance
;
504 sheet
.pszCaption
= load_formatstr(IDS_PERMISSION_FOR
, info
.pszObjectName
);
506 sheet
.nStartPage
= 0;
507 sheet
.phpage
= pages
;
509 ret
= PropertySheetW(&sheet
) != -1;
510 LocalFree((void *)sheet
.pszCaption
);
514 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, void *reserved
)
516 if (reason
== DLL_PROCESS_ATTACH
)
518 aclui_instance
= instance
;
519 DisableThreadLibraryCalls(instance
);