diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 3054ae8a..4467a012 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -334,6 +334,7 @@ patch_enable_all () enable_setupapi_SetupPromptForDisk="$1" enable_sfc_SfcGetNextProtectedFile="$1" enable_shdocvw_ParseURLFromOutsideSource_Tests="$1" + enable_shell32_ACE_Viewer="$1" enable_shell32_Context_Menu="$1" enable_shell32_File_Property_Dialog="$1" enable_shell32_FolderItemsImpl_get_Count="$1" @@ -1234,6 +1235,9 @@ patch_enable () shdocvw-ParseURLFromOutsideSource_Tests) enable_shdocvw_ParseURLFromOutsideSource_Tests="$2" ;; + shell32-ACE_Viewer) + enable_shell32_ACE_Viewer="$2" + ;; shell32-Context_Menu) enable_shell32_Context_Menu="$2" ;; @@ -2195,6 +2199,17 @@ if test "$enable_shell32_SHFileOperation_Win9x" -eq 1; then enable_shell32_Progress_Dialog=1 fi +if test "$enable_shell32_ACE_Viewer" -eq 1; then + if test "$enable_shell32_File_Property_Dialog" -gt 1; then + abort "Patchset shell32-File_Property_Dialog disabled, but shell32-ACE_Viewer depends on that." + fi + if test "$enable_shell32_Progress_Dialog" -gt 1; then + abort "Patchset shell32-Progress_Dialog disabled, but shell32-ACE_Viewer depends on that." + fi + enable_shell32_File_Property_Dialog=1 + enable_shell32_Progress_Dialog=1 +fi + if test "$enable_shell32_Progress_Dialog" -eq 1; then if test "$enable_kernel32_CopyFileEx" -gt 1; then abort "Patchset kernel32-CopyFileEx disabled, but shell32-Progress_Dialog depends on that." @@ -7110,6 +7125,76 @@ if test "$enable_shdocvw_ParseURLFromOutsideSource_Tests" -eq 1; then ) >> "$patchlist" fi +# Patchset shell32-File_Property_Dialog +# | +# | This patchset fixes the following Wine bugs: +# | * [#40426] Implement general tab for file property dialog +# | +# | Modified files: +# | * dlls/shell32/shell32.rc, dlls/shell32/shlview_cmenu.c, dlls/shell32/shresdef.h +# | +if test "$enable_shell32_File_Property_Dialog" -eq 1; then + patch_apply shell32-File_Property_Dialog/0001-shell32-Add-general-tab-in-file-property-dialog.patch + ( + printf '%s\n' '+ { "Michael Müller", "shell32: Add general tab in file property dialog.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset shell32-SHFileOperation_Move +# | +# | This patchset fixes the following Wine bugs: +# | * [#25207] SHFileOperation with FO_MOVE should create new directory on Vista+ +# | +# | Modified files: +# | * dlls/shell32/shlfileop.c, dlls/shell32/tests/shlfileop.c +# | +if test "$enable_shell32_SHFileOperation_Move" -eq 1; then + patch_apply shell32-SHFileOperation_Move/0001-shell32-Fix-SHFileOperation-FO_MOVE-for-creating-sub.patch + ( + printf '%s\n' '+ { "Zhenbo Li", "shell32: Fix SHFileOperation(FO_MOVE) for creating subdirectories.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset shell32-Progress_Dialog +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * server-File_Permissions, ntdll-FileDispositionInformation, kernel32-CopyFileEx, shell32-SHFileOperation_Move +# | +# | Modified files: +# | * dlls/shell32/shell32.rc, dlls/shell32/shlfileop.c, dlls/shell32/shresdef.h +# | +if test "$enable_shell32_Progress_Dialog" -eq 1; then + patch_apply shell32-Progress_Dialog/0001-shell32-Correct-indentation-in-shfileop.c.patch + patch_apply shell32-Progress_Dialog/0002-shell32-Pass-FILE_INFORMATION-into-SHNotify-function.patch + patch_apply shell32-Progress_Dialog/0003-shell32-Implement-file-operation-progress-dialog.patch + patch_apply shell32-Progress_Dialog/0004-shell32-Show-animation-during-SHFileOperation.patch + ( + printf '%s\n' '+ { "Michael Müller", "shell32: Correct indentation in shfileop.c.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "shell32: Pass FILE_INFORMATION into SHNotify* functions.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "shell32: Implement file operation progress dialog.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "shell32: Show animation during SHFileOperation.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset shell32-ACE_Viewer +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * shell32-File_Property_Dialog, server-File_Permissions, ntdll-FileDispositionInformation, kernel32-CopyFileEx, +# | shell32-SHFileOperation_Move, shell32-Progress_Dialog +# | +# | Modified files: +# | * dlls/aclui/Makefile.in, dlls/aclui/aclui.rc, dlls/aclui/aclui_main.c, dlls/aclui/resource.h, dlls/aclui/user_icons.bmp, +# | dlls/shell32/Makefile.in, dlls/shell32/shell32.rc, dlls/shell32/shlview_cmenu.c, dlls/shell32/shresdef.h +# | +if test "$enable_shell32_ACE_Viewer" -eq 1; then + patch_apply shell32-ACE_Viewer/0001-aclui-Add-basic-ACE-viewer.patch + patch_apply shell32-ACE_Viewer/0002-shell32-Add-security-property-tab.patch + ( + printf '%s\n' '+ { "Michael Müller", "aclui: Add basic ACE viewer.", 1 },'; + printf '%s\n' '+ { "Michael Müller", "shell32: Add security property tab.", 1 },'; + ) >> "$patchlist" +fi + # Patchset shell32-Context_Menu # | # | This patchset fixes the following Wine bugs: @@ -7141,21 +7226,6 @@ if test "$enable_shell32_Context_Menu" -eq 1; then ) >> "$patchlist" fi -# Patchset shell32-File_Property_Dialog -# | -# | This patchset fixes the following Wine bugs: -# | * [#40426] Implement general tab for file property dialog -# | -# | Modified files: -# | * dlls/shell32/shell32.rc, dlls/shell32/shlview_cmenu.c, dlls/shell32/shresdef.h -# | -if test "$enable_shell32_File_Property_Dialog" -eq 1; then - patch_apply shell32-File_Property_Dialog/0001-shell32-Add-general-tab-in-file-property-dialog.patch - ( - printf '%s\n' '+ { "Michael Müller", "shell32: Add general tab in file property dialog.", 1 },'; - ) >> "$patchlist" -fi - # Patchset shell32-FolderItemsImpl_get_Count # | # | Modified files: @@ -7229,42 +7299,6 @@ if test "$enable_shell32_Placeholder_Icons" -eq 1; then ) >> "$patchlist" fi -# Patchset shell32-SHFileOperation_Move -# | -# | This patchset fixes the following Wine bugs: -# | * [#25207] SHFileOperation with FO_MOVE should create new directory on Vista+ -# | -# | Modified files: -# | * dlls/shell32/shlfileop.c, dlls/shell32/tests/shlfileop.c -# | -if test "$enable_shell32_SHFileOperation_Move" -eq 1; then - patch_apply shell32-SHFileOperation_Move/0001-shell32-Fix-SHFileOperation-FO_MOVE-for-creating-sub.patch - ( - printf '%s\n' '+ { "Zhenbo Li", "shell32: Fix SHFileOperation(FO_MOVE) for creating subdirectories.", 1 },'; - ) >> "$patchlist" -fi - -# Patchset shell32-Progress_Dialog -# | -# | This patchset has the following (direct or indirect) dependencies: -# | * server-File_Permissions, ntdll-FileDispositionInformation, kernel32-CopyFileEx, shell32-SHFileOperation_Move -# | -# | Modified files: -# | * dlls/shell32/shell32.rc, dlls/shell32/shlfileop.c, dlls/shell32/shresdef.h -# | -if test "$enable_shell32_Progress_Dialog" -eq 1; then - patch_apply shell32-Progress_Dialog/0001-shell32-Correct-indentation-in-shfileop.c.patch - patch_apply shell32-Progress_Dialog/0002-shell32-Pass-FILE_INFORMATION-into-SHNotify-function.patch - patch_apply shell32-Progress_Dialog/0003-shell32-Implement-file-operation-progress-dialog.patch - patch_apply shell32-Progress_Dialog/0004-shell32-Show-animation-during-SHFileOperation.patch - ( - printf '%s\n' '+ { "Michael Müller", "shell32: Correct indentation in shfileop.c.", 1 },'; - printf '%s\n' '+ { "Michael Müller", "shell32: Pass FILE_INFORMATION into SHNotify* functions.", 1 },'; - printf '%s\n' '+ { "Michael Müller", "shell32: Implement file operation progress dialog.", 1 },'; - printf '%s\n' '+ { "Michael Müller", "shell32: Show animation during SHFileOperation.", 1 },'; - ) >> "$patchlist" -fi - # Patchset shell32-RunDLL_CallEntry16 # | # | This patchset fixes the following Wine bugs: diff --git a/patches/shell32-ACE_Viewer/0001-aclui-Add-basic-ACE-viewer.patch b/patches/shell32-ACE_Viewer/0001-aclui-Add-basic-ACE-viewer.patch new file mode 100644 index 00000000..001074a3 --- /dev/null +++ b/patches/shell32-ACE_Viewer/0001-aclui-Add-basic-ACE-viewer.patch @@ -0,0 +1,726 @@ +From 187eb1628d5f74e40e1d37c1924d54c655d6efd0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Mon, 8 May 2017 23:01:28 +0200 +Subject: aclui: Add basic ACE viewer. + +--- + dlls/aclui/Makefile.in | 3 + + dlls/aclui/aclui.rc | 58 ++++++ + dlls/aclui/aclui_main.c | 513 +++++++++++++++++++++++++++++++++++++++++++++- + dlls/aclui/resource.h | 38 ++++ + dlls/aclui/user_icons.bmp | Bin 0 -> 2730 bytes + 5 files changed, 608 insertions(+), 4 deletions(-) + create mode 100644 dlls/aclui/aclui.rc + create mode 100644 dlls/aclui/resource.h + create mode 100644 dlls/aclui/user_icons.bmp + +diff --git a/dlls/aclui/Makefile.in b/dlls/aclui/Makefile.in +index f5b401cbc2c..9d6d0cf39c8 100644 +--- a/dlls/aclui/Makefile.in ++++ b/dlls/aclui/Makefile.in +@@ -1,4 +1,7 @@ + MODULE = aclui.dll + IMPORTLIB = aclui ++IMPORTS = comctl32 user32 advapi32 gdi32 + + C_SRCS = aclui_main.c ++ ++RC_SRCS = aclui.rc +diff --git a/dlls/aclui/aclui.rc b/dlls/aclui/aclui.rc +new file mode 100644 +index 00000000000..08f8b567314 +--- /dev/null ++++ b/dlls/aclui/aclui.rc +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2017 Michael Müller ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "resource.h" ++ ++#define WINE_FILEDESCRIPTION_STR "Wine Security Descriptor Editor" ++#define WINE_FILENAME_STR "aclui.dll" ++#define WINE_FILEVERSION 5,1,2600,5512 ++#define WINE_FILEVERSION_STR "5.1.2600.5512" ++#define WINE_PRODUCTVERSION 5,1,2600,5512 ++#define WINE_PRODUCTVERSION_STR "5.1" ++ ++#include "wine/wine_common_ver.rc" ++ ++#pragma makedep po ++ ++LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT ++ ++IDD_SECURITY_PROPERTIES DIALOGEX 0, 0, 240, 215 ++STYLE DS_SHELLFONT | WS_CHILD | WS_CAPTION ++CAPTION "Security" ++FONT 8, "MS Shell Dlg" ++BEGIN ++ LTEXT "&Group or user names:", -1, 5, 5, 230, 10 ++ CONTROL "", IDC_USERS, "SysListView32", LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | LVS_SORTASCENDING | LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 5, 17, 230, 63, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE ++ PUSHBUTTON "A&dd", IDC_USER_ADD, 110, 85, 60, 15 ++ PUSHBUTTON "&Remove", IDC_USER_REMOVE, 175, 85, 60, 15 ++ ++ LTEXT "", IDC_ACE_USER, 5, 105, 110, 10 ++ LTEXT "Allow", -1, 120, 105, 55, 10, SS_CENTER ++ LTEXT "Deny", -1, 180, 105, 55, 10, SS_CENTER ++ CONTROL "", IDC_ACE, "SysListView32", LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | LVS_SINGLESEL | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 5, 115, 230, 95, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE ++END ++ ++STRINGTABLE ++BEGIN ++ IDS_PERMISSION_FOR "Permissions for %1" ++END ++ ++LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL ++ ++/* @makedep: user_icons.bmp */ ++IDB_USER_ICONS BITMAP user_icons.bmp +diff --git a/dlls/aclui/aclui_main.c b/dlls/aclui/aclui_main.c +index 808f1f09eec..1539ae0d467 100644 +--- a/dlls/aclui/aclui_main.c ++++ b/dlls/aclui/aclui_main.c +@@ -22,17 +22,53 @@ + + #include + ++#define COBJMACROS ++#define NONAMELESSUNION ++ + #include "initguid.h" + #include "windef.h" + #include "winbase.h" + #include "winuser.h" + #include "winnt.h" + #include "aclui.h" ++#include "resource.h" + ++#include "wine/list.h" + #include "wine/debug.h" + + WINE_DEFAULT_DEBUG_CHANNEL(aclui); + ++/* the aclui.h files does not contain the necessary COBJMACROS */ ++#define ISecurityInformation_AddRef(This) (This)->lpVtbl->AddRef(This) ++#define ISecurityInformation_Release(This) (This)->lpVtbl->Release(This) ++#define ISecurityInformation_GetObjectInformation(This, obj) (This)->lpVtbl->GetObjectInformation(This, obj) ++#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 ++{ ++ struct list entry; ++ WCHAR *name; ++ ++ /* must be the last entry */ ++ SID sid; ++}; ++ ++struct security_page ++{ ++ ISecurityInformation *security; ++ SI_OBJECT_INFO info; ++ PSECURITY_DESCRIPTOR sd; ++ SI_ACCESS *access; ++ ULONG access_count; ++ struct list users; ++ ++ HWND dialog; ++ HIMAGELIST image_list_user; ++}; ++ ++static HINSTANCE aclui_instance; ++ + BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) + { + TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); +@@ -42,20 +78,489 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) + case DLL_WINE_PREATTACH: + return FALSE; /* prefer native version */ + case DLL_PROCESS_ATTACH: ++ aclui_instance = hinstDLL; + DisableThreadLibraryCalls(hinstDLL); + break; + } + return TRUE; + } + +-HPROPSHEETPAGE WINAPI CreateSecurityPage(LPSECURITYINFO psi) ++static WCHAR* CDECL load_formatstr(UINT resource, ...) ++{ ++ __ms_va_list valist; ++ WCHAR *str, fmtstr[256]; ++ DWORD ret; ++ ++ if (!LoadStringW(aclui_instance, resource, fmtstr, 256)) ++ return NULL; ++ ++ __ms_va_start( valist, resource ); ++ ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, ++ fmtstr, 0, 0, (WCHAR*)&str, 0, &valist); ++ __ms_va_end( valist ); ++ return ret ? str : NULL; ++} ++ ++static void security_page_free(struct security_page *page) ++{ ++ struct user *user, *user2; ++ ++ LIST_FOR_EACH_ENTRY_SAFE(user, user2, &page->users, struct user, entry) ++ { ++ list_remove(&user->entry); ++ HeapFree(GetProcessHeap(), 0, user->name); ++ HeapFree(GetProcessHeap(), 0, user); ++ } ++ ++ if (page->image_list_user) ImageList_Destroy(page->image_list_user); ++ if (page->security) ISecurityInformation_Release(page->security); ++ HeapFree(GetProcessHeap(), 0, page); ++} ++ ++static void users_clear(struct security_page *page) ++{ ++ struct user *user, *user2; ++ ++ LIST_FOR_EACH_ENTRY_SAFE(user, user2, &page->users, struct user, entry) ++ { ++ /* TODO: Remove from GUI */ ++ ++ list_remove(&user->entry); ++ HeapFree(GetProcessHeap(), 0, user->name); ++ HeapFree(GetProcessHeap(), 0, user); ++ } ++} ++ ++static WCHAR *get_sid_name(PSID sid, SID_NAME_USE *sid_type) + { +- FIXME("(%p): stub\n", psi); ++ 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 = HeapAlloc(GetProcessHeap(), 0, name_len * sizeof(WCHAR)))) ++ return NULL; ++ if (!(domain = HeapAlloc(GetProcessHeap(), 0, domain_len * sizeof(WCHAR)))) ++ goto error; ++ ++ ret = LookupAccountSidW(NULL, sid, name, &name_len, domain, &domain_len, sid_type); ++ HeapFree(GetProcessHeap(), 0, domain); ++ if (ret) return name; ++ ++error: ++ HeapFree(GetProcessHeap(), 0, name); + return NULL; + } + +-BOOL WINAPI EditSecurity(HWND owner, LPSECURITYINFO psi) ++static BOOL users_add(struct security_page *page, PSID sid) + { +- FIXME("(%p, %p): stub\n", owner, psi); ++ SID_NAME_USE sid_type; ++ struct user *user; ++ DWORD sid_len; ++ LVITEMW item; ++ WCHAR *name; ++ ++ /* check if we already processed this user or group */ ++ LIST_FOR_EACH_ENTRY( user, &page->users, struct user, entry ) ++ { ++ if (EqualSid(sid, &user->sid)) ++ return TRUE; ++ } ++ ++ if (!(name = get_sid_name(sid, &sid_type))) ++ return FALSE; ++ ++ sid_len = GetLengthSid(sid); ++ user = HeapAlloc(GetProcessHeap(), 0, offsetof(struct user, sid) + sid_len); ++ if (!user) ++ { ++ HeapFree(GetProcessHeap(), 0, name); ++ return FALSE; ++ } ++ ++ user->name = name; ++ CopySid(sid_len, &user->sid, sid); ++ list_add_tail(&page->users, &user->entry); ++ ++ /* Add in GUI */ ++ item.mask = LVIF_PARAM | LVIF_TEXT; ++ item.iItem = -1; ++ item.iSubItem = 0; ++ item.pszText = name; ++ item.lParam = (LPARAM)user; ++ ++ if (page->image_list_user) ++ { ++ item.mask |= LVIF_IMAGE; ++ item.iImage = (sid_type == SidTypeGroup || sid_type == SidTypeWellKnownGroup) ? 0 : 1; ++ } ++ ++ ListView_InsertItemW(GetDlgItem(page->dialog, IDC_USERS), &item); ++ return TRUE; ++} ++ ++static PSID get_sid_from_ace(ACE_HEADER *ace) ++{ ++ switch (ace->AceType) ++ { ++ case ACCESS_ALLOWED_ACE_TYPE: ++ return (SID *)&((ACCESS_ALLOWED_ACE *)ace)->SidStart; ++ case ACCESS_DENIED_ACE_TYPE: ++ return (SID *)&((ACCESS_DENIED_ACE *)ace)->SidStart; ++ default: ++ FIXME("Don't know how to extract SID from ace type %d\n", ace->AceType); ++ return NULL; ++ } ++} ++ ++static void users_refresh(struct security_page *page) ++{ ++ BOOL defaulted, present; ++ ACE_HEADER *ace; ++ DWORD index; ++ ACL *dacl; ++ PSID sid; ++ ++ users_clear(page); ++ ++ /* Add Owner to list */ ++ if (GetSecurityDescriptorOwner(page->sd, &sid, &defaulted)) ++ users_add(page, sid); ++ ++ /* Everyone else who appears in the DACL */ ++ if (GetSecurityDescriptorDacl(page->sd, &present, &dacl, &defaulted) && present) ++ { ++ for (index = 0; index < dacl->AceCount; index++) ++ { ++ if (!GetAce(dacl, index, (void**)&ace)) ++ break; ++ if (!(sid = get_sid_from_ace(ace))) ++ continue; ++ users_add(page, sid); ++ } ++ } ++} ++ ++static HIMAGELIST create_image_list(UINT resource, UINT width, UINT height, UINT count, COLORREF mask_color) ++{ ++ HIMAGELIST image_list; ++ HBITMAP image; ++ INT ret; ++ ++ if (!(image_list = ImageList_Create(width, height, ILC_COLOR32 | ILC_MASK, 0, count))) ++ return NULL; ++ if (!(image = LoadBitmapW(aclui_instance, MAKEINTRESOURCEW(resource)))) ++ goto error; ++ ++ ret = ImageList_AddMasked(image_list, image, mask_color); ++ DeleteObject(image); ++ if (ret != -1) return image_list; ++ ++error: ++ ImageList_Destroy(image_list); ++ return NULL; ++} ++ ++static void compute_access_masks(PSECURITY_DESCRIPTOR sd, PSID sid, ACCESS_MASK *allowed, ACCESS_MASK *denied) ++{ ++ BOOL defaulted, present; ++ ACE_HEADER *ace; ++ PSID ace_sid; ++ DWORD index; ++ ACL *dacl; ++ ++ *allowed = 0; ++ *denied = 0; ++ ++ if (!GetSecurityDescriptorDacl(sd, &present, &dacl, &defaulted) || !present) ++ return; ++ ++ for (index = 0; index < dacl->AceCount; index++) ++ { ++ if (!GetAce(dacl, index, (void**)&ace)) ++ break; ++ ++ ace_sid = get_sid_from_ace(ace); ++ if (!ace_sid || !EqualSid(ace_sid, sid)) ++ continue; ++ ++ if (ace->AceType == ACCESS_ALLOWED_ACE_TYPE) ++ *allowed |= ((ACCESS_ALLOWED_ACE*)ace)->Mask; ++ else if (ace->AceType == ACCESS_DENIED_ACE_TYPE) ++ *denied |= ((ACCESS_DENIED_ACE*)ace)->Mask; ++ } ++} ++ ++static void show_ace_entries(struct security_page *page, struct user *user) ++{ ++ static const WCHAR yesW[] = {'X',0}; ++ static const WCHAR noW[] = {'-',0}; ++ ++ ACCESS_MASK allowed, denied; ++ WCHAR *infotext; ++ ULONG i, index; ++ LVITEMW item; ++ HWND control; ++ ++ compute_access_masks(page->sd, &user->sid, &allowed, &denied); ++ ++ if ((infotext = load_formatstr(IDS_PERMISSION_FOR, user->name))) ++ { ++ SetDlgItemTextW(page->dialog, IDC_ACE_USER, infotext); ++ LocalFree(infotext); ++ } ++ ++ control = GetDlgItem(page->dialog, IDC_ACE); ++ index = 0; ++ for (i = 0; i < page->access_count; i++) ++ { ++ if (!(page->access[i].dwFlags & SI_ACCESS_GENERAL)) ++ continue; ++ ++ item.mask = LVIF_TEXT; ++ item.iItem = index; ++ ++ item.iSubItem = 1; ++ if ((page->access[i].mask & allowed) == page->access[i].mask) ++ item.pszText = (WCHAR *)yesW; ++ else ++ item.pszText = (WCHAR *)noW; ++ ListView_SetItemW(control, &item); ++ ++ item.iSubItem = 2; ++ if ((page->access[i].mask & denied) == page->access[i].mask) ++ item.pszText = (WCHAR *)yesW; ++ else ++ item.pszText = (WCHAR *)noW; ++ ListView_SetItemW(control, &item); ++ ++ index++; ++ } ++} ++ ++static void create_ace_entries(struct security_page *page) ++{ ++ WCHAR str[256]; ++ HWND control; ++ LVITEMW item; ++ ULONG i, index; ++ ++ control = GetDlgItem(page->dialog, IDC_ACE); ++ index = 0; ++ for (i = 0; i < page->access_count; i++) ++ { ++ if (!(page->access[i].dwFlags & SI_ACCESS_GENERAL)) ++ continue; ++ ++ item.mask = LVIF_TEXT; ++ item.iItem = index; ++ item.iSubItem = 0; ++ if (IS_INTRESOURCE(page->access[i].pszName)) ++ { ++ str[0] = 0; ++ LoadStringW(page->info.hInstance, (UINT)(DWORD_PTR)page->access[i].pszName, str, 256); ++ item.pszText = str; ++ } ++ else ++ item.pszText = (WCHAR *)page->access[i].pszName; ++ ListView_InsertItemW(control, &item); ++ ++ index++; ++ } ++} ++ ++static void security_page_init_dlg(HWND hwnd, struct security_page *page) ++{ ++ LVCOLUMNW column; ++ HWND control; ++ RECT rect; ++ ULONG def = 0; ++ ++ page->dialog = hwnd; ++ ++ if (FAILED(ISecurityInformation_GetSecurity(page->security, DACL_SECURITY_INFORMATION | ++ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, ++ &page->sd, FALSE))) ++ return; ++ ++ if (FAILED(ISecurityInformation_GetAccessRights(page->security, NULL, 0, &page->access, ++ &page->access_count, &def))) ++ return; ++ ++ /* Prepare user list */ ++ 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; ++ ListView_InsertColumnW(control, 0, &column); ++ ++ if ((page->image_list_user = create_image_list(IDB_USER_ICONS, 18, 18, 2, RGB(255, 0, 255)))) ++ SendMessageW(control, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)page->image_list_user); ++ ++ /* Prepare ACE list */ ++ control = GetDlgItem(hwnd, IDC_ACE); ++ SendMessageW(control, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); ++ ++ column.mask = LVCF_FMT | LVCF_WIDTH; ++ column.fmt = LVCFMT_LEFT; ++ column.cx = 170; ++ ListView_InsertColumnW(control, 0, &column); ++ ++ column.mask = LVCF_FMT | LVCF_WIDTH; ++ column.fmt = LVCFMT_CENTER; ++ column.cx = 85; ++ ListView_InsertColumnW(control, 1, &column); ++ ++ column.mask = LVCF_FMT | LVCF_WIDTH; ++ column.fmt = LVCFMT_CENTER; ++ column.cx = 85; ++ ListView_InsertColumnW(control, 2, &column); ++ ++ users_refresh(page); ++ create_ace_entries(page); ++ ++ if (!list_empty(&page->users)) ++ { ++ LVITEMW item; ++ item.mask = LVIF_STATE; ++ item.iItem = 0; ++ item.iSubItem = 0; ++ item.state = LVIS_FOCUSED | LVIS_SELECTED; ++ item.stateMask = item.state; ++ ListView_SetItemW(GetDlgItem(hwnd, IDC_USERS), &item); ++ } ++} ++ ++static INT_PTR CALLBACK security_page_proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) ++{ ++ switch (msg) ++ { ++ case WM_INITDIALOG: ++ { ++ LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam; ++ SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam); ++ security_page_init_dlg(hwndDlg, (struct security_page *)ppsp->lParam); ++ break; ++ } ++ ++ case WM_COMMAND: ++ if (LOWORD(wParam) == IDC_USER_ADD || ++ LOWORD(wParam) == IDC_USER_REMOVE) ++ { ++ /* TODO: Adding & removing users */ ++ MessageBoxA(hwndDlg, "Not implemented yet.", "Error", MB_OK | MB_ICONEXCLAMATION); ++ } ++ break; ++ ++ case WM_NOTIFY: ++ { ++ struct security_page *page = (struct security_page *)GetWindowLongPtrW(hwndDlg, DWLP_USER); ++ NMHDR *hdr = (NMHDR *)lParam; ++ ++ if (hdr->hwndFrom == GetDlgItem(hwndDlg, IDC_USERS) && hdr->code == LVN_ITEMCHANGED) ++ { ++ NMLISTVIEW *nmv = (NMLISTVIEW *)lParam; ++ if (!(nmv->uOldState & LVIS_SELECTED) && (nmv->uNewState & LVIS_SELECTED)) ++ show_ace_entries(page, (struct user *)nmv->lParam); ++ return TRUE; ++ } ++ break; ++ } ++ ++ default: ++ break; ++ } + return FALSE; + } ++ ++static UINT CALLBACK security_page_callback(HWND hwnd, UINT msg, LPPROPSHEETPAGEW ppsp) ++{ ++ struct security_page *page = (struct security_page *)ppsp->lParam; ++ ++ if (msg == PSPCB_RELEASE) ++ security_page_free(page); ++ ++ return 1; ++} ++ ++static HPROPSHEETPAGE create_security_property_page(ISecurityInformation *security) ++{ ++ struct security_page *page; ++ PROPSHEETPAGEW propsheet; ++ HPROPSHEETPAGE ret; ++ ++ if (!(page = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*page)))) ++ return NULL; ++ ++ list_init(&page->users); ++ page->security = security; ++ ISecurityInformation_AddRef(security); ++ ++ if (FAILED(ISecurityInformation_GetObjectInformation(security, &page->info))) ++ goto error; ++ ++ memset(&propsheet, 0, sizeof(propsheet)); ++ propsheet.dwSize = sizeof(propsheet); ++ propsheet.dwFlags = PSP_DEFAULT | PSP_USECALLBACK; ++ propsheet.hInstance = aclui_instance; ++ propsheet.u.pszTemplate = (LPWSTR)MAKEINTRESOURCE(IDD_SECURITY_PROPERTIES); ++ propsheet.pfnDlgProc = security_page_proc; ++ propsheet.pfnCallback = security_page_callback; ++ propsheet.lParam = (LPARAM)page; ++ ++ if (page->info.dwFlags & SI_PAGE_TITLE) ++ { ++ propsheet.pszTitle = page->info.pszPageTitle; ++ propsheet.dwFlags |= PSP_USETITLE; ++ } ++ ++ if ((ret = CreatePropertySheetPageW(&propsheet))) ++ return ret; ++ ++error: ++ security_page_free(page); ++ return NULL; ++} ++ ++HPROPSHEETPAGE WINAPI CreateSecurityPage(LPSECURITYINFO psi) ++{ ++ FIXME("(%p): semi-stub\n", psi); ++ ++ InitCommonControls(); ++ return create_security_property_page(psi); ++} ++ ++BOOL WINAPI EditSecurity(HWND owner, LPSECURITYINFO psi) ++{ ++ PROPSHEETHEADERW prop; ++ HPROPSHEETPAGE pages[1]; ++ SI_OBJECT_INFO info; ++ BOOL ret; ++ ++ TRACE("(%p, %p)\n", owner, psi); ++ ++ if (FAILED(ISecurityInformation_GetObjectInformation(psi, &info))) ++ return FALSE; ++ if (!(pages[0] = CreateSecurityPage(psi))) ++ return FALSE; ++ ++ memset(&prop, 0, sizeof(prop)); ++ prop.dwSize = sizeof(prop); ++ prop.dwFlags = PSH_DEFAULT; ++ prop.hwndParent = owner; ++ prop.hInstance = aclui_instance; ++ prop.pszCaption = load_formatstr(IDS_PERMISSION_FOR, info.pszObjectName); ++ prop.nPages = 1; ++ prop.u2.nStartPage = 0; ++ prop.u3.phpage = pages; ++ ++ ret = PropertySheetW(&prop) != -1; ++ LocalFree((void *)prop.pszCaption); ++ return ret; ++} +diff --git a/dlls/aclui/resource.h b/dlls/aclui/resource.h +new file mode 100644 +index 00000000000..ba3eb8160ab +--- /dev/null ++++ b/dlls/aclui/resource.h +@@ -0,0 +1,38 @@ ++/* ++ * Definitions for aclui dialog controls ++ * ++ * Copyright (c) 2017 Michael Müller ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#ifndef __WINE_ACLUI__ ++#define __WINE_ACLUI__ ++ ++#define IDD_SECURITY_PROPERTIES 100 ++ ++#define IDC_USERS 101 ++#define IDC_USER_ADD 102 ++#define IDC_USER_REMOVE 103 ++ ++#define IDC_ACE_USER 110 ++#define IDC_ACE 111 ++ ++#define IDS_PERMISSION_FOR 1000 ++ ++#define IDB_USER_ICONS 2000 ++#define IDB_CHECKBOX 2001 ++ ++#endif /* __WINE_ACLUI__ */ +diff --git a/dlls/aclui/user_icons.bmp b/dlls/aclui/user_icons.bmp +new file mode 100644 +index 0000000000000000000000000000000000000000..29259e2724ccf67b7e3e84c3fc6d749bc9e8ae26 +GIT binary patch +literal 2730 +zcmdUtc~F#P0LH1N8IS3YY|3(`$+FC$Q3M3!8WF=I!cj3Jj^t)pSCB(Uu2clUR2&33 +zmt$E#SWXd>M2$=FNK;cX1Ox;D6*{J|rkY>xw}vCAo72=EeY4NL`+nd1{Py{t_qBB> +zousF|c8KpNp*Mx52tB1YUGEt&P8ZJ&pS>qB9lg-gyZ_O%U9u`<^ud#kPmfy&di<}{ +zakhb0O*)MQyY8!{B!$ke8g;%$TT?AHpKYKjQ9KWlM+A%)TIkK`T6*g}5L`zZYvknL+p)?dmLW4gBmX{G?_dsa{rOyBm_@A>?UD@ut;exz8p2V*`?1=8)iGhP3WM|43gK1tH7D +z8bj?`$*&atY)>N!!&Z{9b}ngd2BZl8)|L9C$rjUnv2_eX;$7(MM3$P2bJ7mhChsOT +z=mS(TbJRY@6#LC%zs!Utv2O)po-5eN&a=t#v*MUCZVaonEFE>gyQI1rpz=1>`qjSk +z(1bfsn;cG_mytG~lq=p*pDej8P3ojEj2pLaVHO&|OY6Ov?B~V=9~T_mY|#WQL?bt) +zYP}h?p*9TO?4xFrJ%xfVWy(|7^3BomF{~!lPD(-+YqOMycaZ#LLdVm>Idf1&k$5*L +zr_`C0DQBH6m+H&LFk;ksOk3y41SyOES|-TdnIdy0dA*&;V$RV|9jHu{Q+uqL^3Q@f +z6yt!}-<-;AK4Umi&wW?VQyR9MQhyUF6lNRIUT3!80_s7`OHM$Cggh?k>h28 +zI&>v>bAK4a3Cqpm!|HWx_>As^dUy|$rfgQ +z5_m7iMmdusH!x|VKa;{0%naI$S!Nq^vaX|_ah;iIU6?7`*?r{lL!8k(BmLcIBGynF +zX2<4D3M^wQuuMKJbOwvKgKUWoK@+-+k_hL=GS=*jBB1c!%VnsgGA+-_zGkK{AX>BfBTSv(`R +z^T+hxAIrGw{wwxzo0;kq%5=X}UXy3?x;z7;T_^B8G{~M)BgD7d;ls+Cyd^qvEbe$L +zYqY1unO|d`-=lp88+9+HBA4WyExKNmed%xg5y~3gP-HVBxR4n^g-rEHV^-X86m>)F +zJu^bWiD8^Xp4pk#kyUl+ +Date: Mon, 8 May 2017 23:33:45 +0200 +Subject: shell32: Add security property tab. + +--- + dlls/shell32/Makefile.in | 2 +- + dlls/shell32/shell32.rc | 27 +++ + dlls/shell32/shlview_cmenu.c | 383 +++++++++++++++++++++++++++++++++++++++++++ + dlls/shell32/shresdef.h | 27 +++ + 4 files changed, 438 insertions(+), 1 deletion(-) + +diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in +index b12d6169fb5..fd0b49a26d7 100644 +--- a/dlls/shell32/Makefile.in ++++ b/dlls/shell32/Makefile.in +@@ -1,7 +1,7 @@ + EXTRADEFS = -D_SHELL32_ + MODULE = shell32.dll + IMPORTLIB = shell32 +-IMPORTS = uuid shlwapi user32 gdi32 advapi32 ++IMPORTS = uuid shlwapi user32 gdi32 advapi32 aclui + DELAYIMPORTS = ole32 oleaut32 shdocvw version comctl32 gdiplus + EXTRALIBS = $(CORESERVICES_LIBS) + # AUTHORS file is in the top-level directory +diff --git a/dlls/shell32/shell32.rc b/dlls/shell32/shell32.rc +index e11002db92e..11deef73f93 100644 +--- a/dlls/shell32/shell32.rc ++++ b/dlls/shell32/shell32.rc +@@ -205,6 +205,33 @@ the folder?" + IDS_RUNDLG_BROWSE_FILTER_EXE "Executable files (*.exe)" + IDS_RUNDLG_BROWSE_FILTER_ALL "All files (*.*)" + ++ /* Security dialog - General */ ++ IDS_SECURITY_ALL_ACCESS "Full Control" ++ IDS_SECURITY_MODIFY "Modify" ++ IDS_SECURITY_READ_EXEC "Read & Execute" ++ IDS_SECURITY_READ "Read" ++ IDS_SECURITY_WRITE "Write" ++ IDS_SECURITY_DIR_LIST "List Folder Contents" ++ ++ /* Security dialog - Advanced */ ++ IDS_SECURITY_TRAVERSE "Traverse Folder" ++ IDS_SECURITY_EXECUTE "Execute File" ++ IDS_SECURITY_LIST_FOLDER "List Folder" ++ IDS_SECURITY_READ_DATA "Read Data" ++ IDS_SECURITY_READ_ATTR "Read Attributes" ++ IDS_SECURITY_READ_EX_ATTR "Read Extended Attributes" ++ IDS_SECURITY_CREATE_FILES "Create Files" ++ IDS_SECURITY_WRITE_DATA "Write Data" ++ IDS_SEUCRITY_CREATE_FOLDER "Create Folders" ++ IDS_SECURITY_APPEND_DATA "Append Data" ++ IDS_SECURITY_WRITE_ATTR "Write Attributes" ++ IDS_SECURITY_WRITE_EX_ATTR "Write Extended Attributes" ++ IDS_SECURITY_DELETE_CHILD "Delete Subfolders and Files" ++ IDS_SECURITY_DELETE "Delete" ++ IDS_SECURITY_READ_PERM "Read Permissions" ++ IDS_SECURITY_CHANGE_PERM "Change Permissions" ++ IDS_SECURITY_CHANGE_OWNER "Take Ownership" ++ + /* shell folder path default values */ + /* FIXME: Some will be unused until desktop.ini support is implemented */ + IDS_PROGRAMS "Programs" +diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c +index 50b4da11014..7545c598b39 100644 +--- a/dlls/shell32/shlview_cmenu.c ++++ b/dlls/shell32/shlview_cmenu.c +@@ -40,9 +40,128 @@ + + #include "shresdef.h" + #include "shlwapi.h" ++#include "aclui.h" ++#include "aclapi.h" ++ ++/* Small hack: We need to remove DECLSPEC_HIDDEN from the aclui export. */ ++const GUID IID_ISecurityInformation = {0x965fc360, 0x16ff, 0x11d0, {0x91, 0xcb, 0x0, 0xaa, 0x0, 0xbb, 0xb7, 0x23}}; + + WINE_DEFAULT_DEBUG_CHANNEL(shell); + ++/* According to https://blogs.msdn.microsoft.com/oldnewthing/20070726-00/?p=25833 */ ++static const SI_ACCESS access_rights_files[] = ++{ ++ /* General access rights */ ++ { ++ &GUID_NULL, ++ FILE_ALL_ACCESS, MAKEINTRESOURCEW(IDS_SECURITY_ALL_ACCESS), ++ SI_ACCESS_GENERAL ++ }, ++ { ++ &GUID_NULL, ++ FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE, ++ MAKEINTRESOURCEW(IDS_SECURITY_MODIFY), ++ SI_ACCESS_GENERAL ++ }, ++ { ++ &GUID_NULL, ++ FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, ++ MAKEINTRESOURCEW(IDS_SECURITY_READ_EXEC), ++ SI_ACCESS_GENERAL ++ }, ++ { ++ &GUID_NULL, ++ FILE_GENERIC_READ, ++ MAKEINTRESOURCEW(IDS_SECURITY_READ), ++ SI_ACCESS_GENERAL ++ }, ++ { ++ &GUID_NULL, ++ FILE_GENERIC_WRITE & ~READ_CONTROL, ++ MAKEINTRESOURCEW(IDS_SECURITY_WRITE), ++ SI_ACCESS_GENERAL ++ }, ++ ++ /* Advanced permissions */ ++ { &GUID_NULL, FILE_ALL_ACCESS, MAKEINTRESOURCEW(IDS_SECURITY_ALL_ACCESS), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_EXECUTE, MAKEINTRESOURCEW(IDS_SECURITY_EXECUTE), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_READ_DATA, MAKEINTRESOURCEW(IDS_SECURITY_READ_DATA), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_READ_ATTRIBUTES, MAKEINTRESOURCEW(IDS_SECURITY_READ_ATTR), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_READ_EA, MAKEINTRESOURCEW(IDS_SECURITY_READ_EX_ATTR), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_WRITE_DATA, MAKEINTRESOURCEW(IDS_SECURITY_WRITE_DATA), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_APPEND_DATA, MAKEINTRESOURCEW(IDS_SECURITY_APPEND_DATA), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_WRITE_ATTRIBUTES, MAKEINTRESOURCEW(IDS_SECURITY_WRITE_ATTR), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_WRITE_EA, MAKEINTRESOURCEW(IDS_SECURITY_WRITE_EX_ATTR), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, DELETE, MAKEINTRESOURCEW(IDS_SECURITY_DELETE), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, READ_CONTROL, MAKEINTRESOURCEW(IDS_SECURITY_READ_PERM), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCEW(IDS_SECURITY_CHANGE_PERM), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCEW(IDS_SECURITY_CHANGE_OWNER), SI_ACCESS_SPECIFIC }, ++}; ++ ++static const SI_ACCESS access_rights_directories[] = ++{ ++ /* General access rights */ ++ { ++ &GUID_NULL, ++ FILE_ALL_ACCESS, ++ MAKEINTRESOURCEW(IDS_SECURITY_ALL_ACCESS), ++ SI_ACCESS_GENERAL ++ }, ++ { ++ &GUID_NULL, ++ FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE, ++ MAKEINTRESOURCEW(IDS_SECURITY_MODIFY), ++ SI_ACCESS_GENERAL ++ }, ++ { ++ &GUID_NULL, ++ FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, ++ MAKEINTRESOURCEW(IDS_SECURITY_DIR_LIST), ++ SI_ACCESS_GENERAL ++ }, ++ { ++ &GUID_NULL, ++ FILE_GENERIC_READ, ++ MAKEINTRESOURCEW(IDS_SECURITY_READ), ++ SI_ACCESS_GENERAL ++ }, ++ { ++ &GUID_NULL, ++ FILE_GENERIC_WRITE & ~READ_CONTROL, ++ MAKEINTRESOURCEW(IDS_SECURITY_WRITE), ++ SI_ACCESS_GENERAL ++ }, ++ ++ /* Advanced permissions */ ++ { &GUID_NULL, FILE_ALL_ACCESS, MAKEINTRESOURCEW(IDS_SECURITY_ALL_ACCESS), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_TRAVERSE, MAKEINTRESOURCEW(IDS_SECURITY_TRAVERSE), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_LIST_DIRECTORY, MAKEINTRESOURCEW(IDS_SECURITY_LIST_FOLDER), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_READ_ATTRIBUTES, MAKEINTRESOURCEW(IDS_SECURITY_READ_ATTR), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_READ_EA, MAKEINTRESOURCEW(IDS_SECURITY_READ_EX_ATTR), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_ADD_FILE, MAKEINTRESOURCEW(IDS_SECURITY_CREATE_FILES), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_ADD_SUBDIRECTORY, MAKEINTRESOURCEW(IDS_SEUCRITY_CREATE_FOLDER), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_WRITE_ATTRIBUTES, MAKEINTRESOURCEW(IDS_SECURITY_WRITE_ATTR), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_WRITE_EA, MAKEINTRESOURCEW(IDS_SECURITY_WRITE_EX_ATTR), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, FILE_DELETE_CHILD, MAKEINTRESOURCEW(IDS_SECURITY_DELETE_CHILD), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, DELETE, MAKEINTRESOURCEW(IDS_SECURITY_DELETE), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, READ_CONTROL, MAKEINTRESOURCEW(IDS_SECURITY_READ_PERM), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCEW(IDS_SECURITY_CHANGE_PERM), SI_ACCESS_SPECIFIC }, ++ { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCEW(IDS_SECURITY_CHANGE_OWNER), SI_ACCESS_SPECIFIC }, ++}; ++ ++struct FileSecurity ++{ ++ ISecurityInformation ISecurityInformation_iface; ++ LONG ref; ++ WCHAR *path; ++ BOOL directory; ++}; ++ ++static inline struct FileSecurity *impl_from_ISecurityInformation(ISecurityInformation *iface) ++{ ++ return CONTAINING_RECORD(iface, struct FileSecurity, ISecurityInformation_iface); ++} ++ + typedef struct + { + IContextMenu3 IContextMenu3_iface; +@@ -684,6 +803,269 @@ error: + HeapFree(GetProcessHeap(), 0, props); + } + ++static HRESULT WINAPI filesecurity_QueryInterface(ISecurityInformation *iface, REFIID riid, void **ppv) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ++ if (IsEqualGUID(&IID_IUnknown, riid)) ++ { ++ TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); ++ *ppv = &This->ISecurityInformation_iface; ++ } ++ else if (IsEqualGUID(&IID_ISecurityInformation, riid)) ++ { ++ TRACE("(%p)->(IID_ISecurityInformation %p)\n", This, ppv); ++ *ppv = &This->ISecurityInformation_iface; ++ } ++ else ++ { ++ *ppv = NULL; ++ WARN("Unsupported interface %s\n", debugstr_guid(riid)); ++ return E_NOINTERFACE; ++ } ++ ++ IUnknown_AddRef((IUnknown *)*ppv); ++ return S_OK; ++} ++ ++static ULONG WINAPI filesecurity_AddRef(ISecurityInformation *iface) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ++ TRACE("(%p)\n", This); ++ ++ return InterlockedIncrement(&This->ref); ++} ++ ++static ULONG WINAPI filesecurity_Release(ISecurityInformation *iface) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ULONG ref; ++ ++ TRACE("(%p)\n", This); ++ ++ ref = InterlockedDecrement(&This->ref); ++ if (!ref) ++ { ++ HeapFree(GetProcessHeap(), 0, This->path); ++ HeapFree(GetProcessHeap(), 0, This); ++ } ++ ++ return ref; ++} ++ ++static HRESULT WINAPI filesecurity_GetObjectInformation(ISecurityInformation *iface, SI_OBJECT_INFO *info) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ++ TRACE("(%p, %p)\n", This, info); ++ ++ info->dwFlags = SI_ADVANCED; ++ info->hInstance = shell32_hInstance; ++ info->pszServerName = NULL; ++ info->pszObjectName = This->path; ++ info->pszPageTitle = NULL; ++ memcpy(&info->guidObjectType, &GUID_NULL, sizeof(GUID)); ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI filesecurity_GetSecurity(ISecurityInformation *iface, SECURITY_INFORMATION info, PSECURITY_DESCRIPTOR *sd, BOOL default_sd) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ++ TRACE("(%p, %u, %p, %u)\n", This, info, sd, default_sd); ++ ++ if (default_sd) ++ FIXME("Returning a default sd is not implemented\n"); ++ ++ if (GetNamedSecurityInfoW(This->path, SE_FILE_OBJECT, info, NULL, NULL, NULL, NULL, sd) != ERROR_SUCCESS) ++ return E_FAIL; ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI filesecurity_SetSecurity(ISecurityInformation *iface, SECURITY_INFORMATION info, PSECURITY_DESCRIPTOR sd) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ BOOL present, defaulted; ++ PSID owner, group; ++ ACL *dacl, *sacl; ++ ++ TRACE("(%p, %u, %p)\n", This, info, sd); ++ ++ if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) ++ return E_FAIL; ++ ++ if (!GetSecurityDescriptorGroup(sd, &group, &defaulted)) ++ return E_FAIL; ++ ++ if (!GetSecurityDescriptorDacl(sd, &present, &dacl, &defaulted)) ++ return E_FAIL; ++ if (!present) dacl = NULL; ++ ++ if (!GetSecurityDescriptorSacl(sd, &present, &sacl, &defaulted)) ++ return E_FAIL; ++ if (!present) sacl = NULL; ++ ++ if (SetNamedSecurityInfoW(This->path, SE_FILE_OBJECT, info, owner, group, dacl, sacl) != ERROR_SUCCESS) ++ return E_FAIL; ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI filesecurity_GetAccessRights(ISecurityInformation *iface, const GUID* type, DWORD flags, SI_ACCESS **access, ++ ULONG *count, ULONG *default_access ) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ++ TRACE("(%p, %s, %x, %p, %p, %p)\n", This, debugstr_guid(type), flags, access, count, default_access); ++ ++ if (This->directory) ++ { ++ *access = (SI_ACCESS *)access_rights_directories; ++ *count = sizeof(access_rights_directories) / sizeof(access_rights_directories[0]); ++ } ++ else ++ { ++ *access = (SI_ACCESS *)access_rights_files; ++ *count = sizeof(access_rights_files) / sizeof(access_rights_files[0]); ++ } ++ ++ *default_access = 0; ++ return S_OK; ++} ++ ++static HRESULT WINAPI filesecurity_MapGeneric(ISecurityInformation *iface, const GUID *type, UCHAR *ace_flags, ACCESS_MASK *mask) ++{ ++ static GENERIC_MAPPING file_access_map = ++ { ++ FILE_GENERIC_READ, ++ FILE_GENERIC_WRITE, ++ FILE_GENERIC_EXECUTE, ++ FILE_ALL_ACCESS ++ }; ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ++ FIXME("(%p, %s, %p, %p): semi-stub!\n", This, debugstr_guid(type), ace_flags, mask); ++ ++ MapGenericMask((DWORD*)mask, &file_access_map); ++ return S_OK; ++} ++ ++static HRESULT WINAPI filesecurity_GetInheritTypes(ISecurityInformation *iface, PSI_INHERIT_TYPE *types, ULONG *count) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ++ FIXME("(%p, %p, %p): stub!\n", This, types, count); ++ ++ *types = NULL; ++ *count = 0; ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI filesecurity_PropertySheetPageCallback(ISecurityInformation *iface, HWND hwnd, UINT msg, SI_PAGE_TYPE page) ++{ ++ struct FileSecurity *This = impl_from_ISecurityInformation(iface); ++ ++ TRACE("(%p, %p, %u, %u)\n", This, hwnd, msg, page); ++ return S_OK; ++} ++ ++static const struct ISecurityInformationVtbl filesecurity_vtbl = ++{ ++ /* IUnknown */ ++ filesecurity_QueryInterface, ++ filesecurity_AddRef, ++ filesecurity_Release, ++ /* ISecurityInformation */ ++ filesecurity_GetObjectInformation, ++ filesecurity_GetSecurity, ++ filesecurity_SetSecurity, ++ filesecurity_GetAccessRights, ++ filesecurity_MapGeneric, ++ filesecurity_GetInheritTypes, ++ filesecurity_PropertySheetPageCallback, ++}; ++ ++static ISecurityInformation *create_filesecurity_information(WCHAR *path, BOOL directory) ++{ ++ struct FileSecurity *security; ++ DWORD len; ++ ++ security = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*security)); ++ if (!security) return NULL; ++ ++ security->ISecurityInformation_iface.lpVtbl = &filesecurity_vtbl; ++ security->ref = 1; ++ security->directory = directory; ++ ++ len = (strlenW(path) + 1) * sizeof(WCHAR); ++ security->path = HeapAlloc(GetProcessHeap(), 0, len); ++ if (!security->path) goto error; ++ ++ memcpy(security->path, path, len); ++ return &security->ISecurityInformation_iface; ++ ++error: ++ HeapFree(GetProcessHeap(), 0, security); ++ return NULL; ++} ++ ++static void init_security_properties_pages(IDataObject *pDo, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) ++{ ++ ISecurityInformation *security; ++ HPROPSHEETPAGE security_page; ++ FORMATETC format; ++ STGMEDIUM stgm; ++ DWORD attrib; ++ WCHAR *path; ++ UINT len; ++ ++ format.cfFormat = CF_HDROP; ++ format.ptd = NULL; ++ format.dwAspect = DVASPECT_CONTENT; ++ format.lindex = -1; ++ format.tymed = TYMED_HGLOBAL; ++ ++ if (FAILED(IDataObject_GetData(pDo, &format, &stgm))) ++ return; ++ ++ if (!(len = DragQueryFileW((HDROP)stgm.DUMMYUNIONNAME.hGlobal, 0, NULL, 0))) ++ { ++ ReleaseStgMedium(&stgm); ++ return; ++ } ++ ++ if (!(path = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) ++ { ++ ReleaseStgMedium(&stgm); ++ return; ++ } ++ ++ len = DragQueryFileW((HDROP)stgm.DUMMYUNIONNAME.hGlobal, 0, path, len + 1); ++ ReleaseStgMedium(&stgm); ++ if (!len) goto done; ++ ++ attrib = GetFileAttributesW(path); ++ if (attrib == INVALID_FILE_ATTRIBUTES) ++ goto done; ++ ++ if (!(security = create_filesecurity_information(path, attrib & FILE_ATTRIBUTE_DIRECTORY))) ++ goto done; ++ ++ security_page = CreateSecurityPage(security); ++ IUnknown_Release((IUnknown *)security); ++ if (!security_page) goto done; ++ ++ lpfnAddPage(security_page, lParam); ++ ++done: ++ HeapFree(GetProcessHeap(), 0, path); ++} ++ ++ + #define MAX_PROP_PAGES 99 + + static void DoOpenProperties(ContextMenu *This, HWND hwnd) +@@ -766,6 +1148,7 @@ static void DoOpenProperties(ContextMenu *This, HWND hwnd) + if (SUCCEEDED(ret)) + { + init_file_properties_pages(lpDo, Properties_AddPropSheetCallback, (LPARAM)&psh); ++ init_security_properties_pages(lpDo, Properties_AddPropSheetCallback, (LPARAM)&psh); + + hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletype, MAX_PROP_PAGES - psh.nPages, lpDo); + if (hpsxa != NULL) +diff --git a/dlls/shell32/shresdef.h b/dlls/shell32/shresdef.h +index 1445077b86e..974da3c7ab5 100644 +--- a/dlls/shell32/shresdef.h ++++ b/dlls/shell32/shresdef.h +@@ -157,6 +157,33 @@ + #define IDS_FILEOP_FROM 337 + #define IDS_FILEOP_PREFLIGHT 338 + ++/* Strings for security dialog - General */ ++#define IDS_SECURITY_ALL_ACCESS 340 ++#define IDS_SECURITY_MODIFY 341 ++#define IDS_SECURITY_READ_EXEC 342 ++#define IDS_SECURITY_READ 343 ++#define IDS_SECURITY_WRITE 344 ++#define IDS_SECURITY_DIR_LIST 345 ++ ++/* Strings for security dialog - Advanced */ ++#define IDS_SECURITY_TRAVERSE 346 ++#define IDS_SECURITY_EXECUTE 347 ++#define IDS_SECURITY_LIST_FOLDER 348 ++#define IDS_SECURITY_READ_DATA 349 ++#define IDS_SECURITY_READ_ATTR 350 ++#define IDS_SECURITY_READ_EX_ATTR 351 ++#define IDS_SECURITY_CREATE_FILES 352 ++#define IDS_SECURITY_WRITE_DATA 353 ++#define IDS_SEUCRITY_CREATE_FOLDER 354 ++#define IDS_SECURITY_APPEND_DATA 355 ++#define IDS_SECURITY_WRITE_ATTR 356 ++#define IDS_SECURITY_WRITE_EX_ATTR 357 ++#define IDS_SECURITY_DELETE_CHILD 358 ++#define IDS_SECURITY_DELETE 359 ++#define IDS_SECURITY_READ_PERM 360 ++#define IDS_SECURITY_CHANGE_PERM 361 ++#define IDS_SECURITY_CHANGE_OWNER 362 ++ + /* Note: this string is referenced from the registry*/ + #define IDS_RECYCLEBIN_FOLDER_NAME 8964 + +-- +2.12.2 + diff --git a/patches/shell32-ACE_Viewer/definition b/patches/shell32-ACE_Viewer/definition new file mode 100644 index 00000000..89c8df2f --- /dev/null +++ b/patches/shell32-ACE_Viewer/definition @@ -0,0 +1,3 @@ +Fixes: Implement a basic security property tab +Depends: shell32-Progress_Dialog +Depends: shell32-File_Property_Dialog