diff --git a/dlls/aclui/Makefile.in b/dlls/aclui/Makefile.in index da3aa00084e..f93e5da6c8d 100644 --- a/dlls/aclui/Makefile.in +++ b/dlls/aclui/Makefile.in @@ -1,6 +1,6 @@ MODULE = aclui.dll IMPORTLIB = aclui -IMPORTS = comctl32 user32 +IMPORTS = comctl32 user32 advapi32 EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native diff --git a/dlls/aclui/aclui_main.c b/dlls/aclui/aclui_main.c index 3989c3017aa..199e7295adc 100644 --- a/dlls/aclui/aclui_main.c +++ b/dlls/aclui/aclui_main.c @@ -39,23 +39,178 @@ WINE_DEFAULT_DEBUG_CHANNEL(aclui); #define ISecurityInformation_GetSecurity(This, info, sd, def) (This)->lpVtbl->GetSecurity(This, info, sd, def) #define ISecurityInformation_GetAccessRights(This, type, flags, access, count, def) (This)->lpVtbl->GetAccessRights(This, type, flags, access, count, def) +struct user +{ + WCHAR *name; + PSID sid; +}; + struct security_page { + ISecurityInformation *security; SI_OBJECT_INFO info; + PSECURITY_DESCRIPTOR sd; + + struct user *users; + unsigned int user_count; HWND dialog; }; static HINSTANCE aclui_instance; +static WCHAR *get_sid_name(PSID sid, SID_NAME_USE *sid_type) +{ + WCHAR *name, *domain; + DWORD domain_len = 0; + DWORD name_len = 0; + BOOL ret; + + LookupAccountSidW(NULL, sid, NULL, &name_len, NULL, &domain_len, sid_type); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return NULL; + if (!(name = malloc(name_len * sizeof(WCHAR)))) + return NULL; + if (!(domain = malloc(domain_len * sizeof(WCHAR)))) + { + free(name); + return NULL; + } + + ret = LookupAccountSidW(NULL, sid, name, &name_len, domain, &domain_len, sid_type); + free(domain); + if (ret) return name; + free(name); + return NULL; +} + +static void add_user(struct security_page *page, PSID sid) +{ + struct user *new_array, *user; + SID_NAME_USE sid_type; + unsigned int i; + LVITEMW item; + WCHAR *name; + + /* check if we already processed this user or group */ + for (i = 0; i < page->user_count; ++i) + { + if (EqualSid(sid, page->users[i].sid)) + return; + } + + if (!(name = get_sid_name(sid, &sid_type))) + return; + + if (!(new_array = realloc(page->users, (page->user_count + 1) * sizeof(*page->users)))) + return; + page->users = new_array; + user = &page->users[page->user_count++]; + + user->name = name; + user->sid = sid; + + item.mask = LVIF_PARAM | LVIF_TEXT; + item.iItem = -1; + item.iSubItem = 0; + item.pszText = name; + item.lParam = (LPARAM)user; + + SendMessageW(GetDlgItem(page->dialog, IDC_USERS), LVM_INSERTITEMW, 0, (LPARAM)&item); +} + +static PSID get_sid_from_ace(ACE_HEADER *ace) +{ + switch (ace->AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: + return &((ACCESS_ALLOWED_ACE *)ace)->SidStart; + case ACCESS_DENIED_ACE_TYPE: + return &((ACCESS_DENIED_ACE *)ace)->SidStart; + default: + FIXME("Unhandled ACE type %#x.\n", ace->AceType); + return NULL; + } +} + +static void init_users(struct security_page *page) +{ + BOOL defaulted, present; + ACE_HEADER *ace; + DWORD index; + ACL *dacl; + PSID sid; + + if (!GetSecurityDescriptorDacl(page->sd, &present, &dacl, &defaulted)) + { + ERR("Failed to query descriptor information, error %u.\n", GetLastError()); + return; + } + + if (!present) + return; + + for (index = 0; index < dacl->AceCount; index++) + { + if (!GetAce(dacl, index, (void **)&ace)) + break; + if (!(sid = get_sid_from_ace(ace))) + continue; + add_user(page, sid); + } +} + static void security_page_free(struct security_page *page) { + unsigned int i; + + for (i = 0; i < page->user_count; ++i) + free(page->users[i].name); + free(page->users); + + LocalFree(page->sd); + if (page->security) + ISecurityInformation_Release(page->security); free(page); } static void security_page_init_dlg(HWND hwnd, struct security_page *page) { + LVCOLUMNW column; + HWND control; + HRESULT hr; + RECT rect; + page->dialog = hwnd; + + if (FAILED(hr = ISecurityInformation_GetSecurity(page->security, + DACL_SECURITY_INFORMATION, &page->sd, FALSE))) + { + ERR("Failed to get security descriptor, hr %#x.\n", hr); + return; + } + + control = GetDlgItem(hwnd, IDC_USERS); + SendMessageW(control, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); + + GetClientRect(control, &rect); + column.mask = LVCF_FMT | LVCF_WIDTH; + column.fmt = LVCFMT_LEFT; + column.cx = rect.right - rect.left; + SendMessageW(control, LVM_INSERTCOLUMNW, 0, (LPARAM)&column); + + init_users(page); + + if (page->user_count) + { + LVITEMW item; + item.mask = LVIF_STATE; + item.iItem = 0; + item.iSubItem = 0; + item.state = LVIS_FOCUSED | LVIS_SELECTED; + item.stateMask = item.state; + SendMessageW(control, LVM_SETITEMW, 0, (LPARAM)&item); + } } static INT_PTR CALLBACK security_page_proc(HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam) @@ -101,6 +256,9 @@ HPROPSHEETPAGE WINAPI CreateSecurityPage(ISecurityInformation *security) return NULL; } + page->security = security; + ISecurityInformation_AddRef(security); + memset(&propsheet, 0, sizeof(propsheet)); propsheet.dwSize = sizeof(propsheet); propsheet.dwFlags = PSP_DEFAULT | PSP_USECALLBACK; @@ -119,6 +277,7 @@ HPROPSHEETPAGE WINAPI CreateSecurityPage(ISecurityInformation *security) if (!(ret = CreatePropertySheetPageW(&propsheet))) { ERR("Failed to create property sheet page.\n"); + ISecurityInformation_Release(security); free(page); return NULL; }