From: Zebediah Figura Subject: [PATCH 2/2] shell32: Add security property tab. Message-Id: <20210218053217.369520-2-z.figura12@gmail.com> Date: Wed, 17 Feb 2021 23:32:17 -0600 In-Reply-To: <20210218053217.369520-1-z.figura12@gmail.com> References: <20210218053217.369520-1-z.figura12@gmail.com> From: Michael Müller Signed-off-by: Zebediah Figura --- dlls/shell32/Makefile.in | 2 +- dlls/shell32/shell32.rc | 20 +++ dlls/shell32/shlview_cmenu.c | 302 +++++++++++++++++++++++++++++++++++ dlls/shell32/shresdef.h | 20 +++ 4 files changed, 343 insertions(+), 1 deletion(-) diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in index fe49bf09f98..f6fcf2e18eb 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 # AUTHORS file is in the top-level directory EXTRAINCL = -I$(top_srcdir) diff --git a/dlls/shell32/shell32.rc b/dlls/shell32/shell32.rc index f19b09f8c21..ce5daea1e8b 100644 --- a/dlls/shell32/shell32.rc +++ b/dlls/shell32/shell32.rc @@ -197,6 +197,26 @@ the folder?" IDS_RUNDLG_BROWSE_FILTER_EXE "Executable files (*.exe)" IDS_RUNDLG_BROWSE_FILTER_ALL "All files (*.*)" + IDS_SECURITY_ADD_FILE "Add File" + IDS_SECURITY_ADD_SUBDIRECTORY "Add Subdirectory" + IDS_SECURITY_ALL_ACCESS "All Access" + IDS_SECURITY_APPEND_DATA "Append Data" + IDS_SECURITY_DELETE "Delete" + IDS_SECURITY_DELETE_CHILD "Delete Child" + IDS_SECURITY_EXECUTE "Execute" + IDS_SECURITY_LIST_DIRECTORY "List Directory Contents" + IDS_SECURITY_READ_ATTRIBUTES "Read Attributes" + IDS_SECURITY_READ_CONTROL "Read Security Descriptor" + IDS_SECURITY_READ_DATA "Read Data" + IDS_SECURITY_READ_EA "Read Extended Attributes" + IDS_SECURITY_SYNCHRONIZE "Synchronize" + IDS_SECURITY_TRAVERSE "Traverse" + IDS_SECURITY_WRITE_ATTRIBUTES "Write Attributes" + IDS_SECURITY_WRITE_DAC "Write DACL" + IDS_SECURITY_WRITE_DATA "Write Data" + IDS_SECURITY_WRITE_EA "Write Extended Attributes" + IDS_SECURITY_WRITE_OWNER "Write Owner" + /* 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 04ac0b6fd3c..86b84a3ca67 100644 --- a/dlls/shell32/shlview_cmenu.c +++ b/dlls/shell32/shlview_cmenu.c @@ -39,12 +39,68 @@ #include "shresdef.h" #include "shlwapi.h" +#include "initguid.h" +#include "aclui.h" +#include "aclapi.h" #include "wine/heap.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); +#define X(a, b) {&GUID_NULL, a, MAKEINTRESOURCEW(b), SI_ACCESS_GENERAL}, + +static const SI_ACCESS access_rights_file[] = +{ + X(FILE_ALL_ACCESS, IDS_SECURITY_ALL_ACCESS) + X(FILE_READ_DATA, IDS_SECURITY_READ_DATA) + X(FILE_WRITE_DATA, IDS_SECURITY_WRITE_DATA) + X(FILE_APPEND_DATA, IDS_SECURITY_APPEND_DATA) + X(FILE_READ_EA, IDS_SECURITY_READ_EA) + X(FILE_WRITE_EA, IDS_SECURITY_WRITE_EA) + X(FILE_EXECUTE, IDS_SECURITY_EXECUTE) + X(FILE_READ_ATTRIBUTES, IDS_SECURITY_READ_ATTRIBUTES) + X(FILE_WRITE_ATTRIBUTES, IDS_SECURITY_WRITE_ATTRIBUTES) + X(DELETE, IDS_SECURITY_DELETE) + X(READ_CONTROL, IDS_SECURITY_READ_CONTROL) + X(WRITE_DAC, IDS_SECURITY_WRITE_DAC) + X(WRITE_OWNER, IDS_SECURITY_WRITE_OWNER) + X(SYNCHRONIZE, IDS_SECURITY_SYNCHRONIZE) +}; + +static const SI_ACCESS access_rights_directory[] = +{ + X(FILE_ALL_ACCESS, IDS_SECURITY_ALL_ACCESS) + X(FILE_LIST_DIRECTORY, IDS_SECURITY_LIST_DIRECTORY) + X(FILE_ADD_FILE, IDS_SECURITY_ADD_FILE) + X(FILE_ADD_SUBDIRECTORY, IDS_SECURITY_ADD_SUBDIRECTORY) + X(FILE_READ_EA, IDS_SECURITY_READ_EA) + X(FILE_WRITE_EA, IDS_SECURITY_WRITE_EA) + X(FILE_TRAVERSE, IDS_SECURITY_TRAVERSE) + X(FILE_DELETE_CHILD, IDS_SECURITY_DELETE_CHILD) + X(FILE_READ_ATTRIBUTES, IDS_SECURITY_READ_ATTRIBUTES) + X(FILE_WRITE_ATTRIBUTES, IDS_SECURITY_WRITE_ATTRIBUTES) + X(DELETE, IDS_SECURITY_DELETE) + X(READ_CONTROL, IDS_SECURITY_READ_CONTROL) + X(WRITE_DAC, IDS_SECURITY_WRITE_DAC) + X(WRITE_OWNER, IDS_SECURITY_WRITE_OWNER) + X(SYNCHRONIZE, IDS_SECURITY_SYNCHRONIZE) +}; +#undef X + +struct security_info +{ + ISecurityInformation ISecurityInformation_iface; + LONG refcount; + WCHAR *path; + BOOL directory; +}; + +static inline struct security_info *impl_from_ISecurityInformation(ISecurityInformation *iface) +{ + return CONTAINING_RECORD(iface, struct security_info, ISecurityInformation_iface); +} + typedef struct { IContextMenu3 IContextMenu3_iface; @@ -615,6 +671,251 @@ error: heap_free(props); } +static HRESULT WINAPI security_info_QueryInterface(ISecurityInformation *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_ISecurityInformation)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + else + { + *out = NULL; + WARN("%s is not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } +} + +static ULONG WINAPI security_info_AddRef(ISecurityInformation *iface) +{ + struct security_info *info = impl_from_ISecurityInformation(iface); + ULONG refcount = InterlockedIncrement(&info->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI security_info_Release(ISecurityInformation *iface) +{ + struct security_info *info = impl_from_ISecurityInformation(iface); + ULONG refcount = InterlockedIncrement(&info->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount) + { + HeapFree(GetProcessHeap(), 0, info->path); + HeapFree(GetProcessHeap(), 0, info); + } + + return refcount; +} + +static HRESULT WINAPI security_info_GetObjectInformation(ISecurityInformation *iface, SI_OBJECT_INFO *out) +{ + struct security_info *info = impl_from_ISecurityInformation(iface); + + TRACE("iface %p, out %p.\n", iface, out); + + memset(out, 0, sizeof(*out)); + out->dwFlags = SI_ADVANCED; + out->hInstance = shell32_hInstance; + out->pszObjectName = info->path; + + return S_OK; +} + +static HRESULT WINAPI security_info_GetSecurity(ISecurityInformation *iface, + SECURITY_INFORMATION mask, PSECURITY_DESCRIPTOR *sd, BOOL default_sd) +{ + struct security_info *info = impl_from_ISecurityInformation(iface); + + TRACE("iface %p, mask %#x, sd %p, default_sd %d.\n", iface, mask, sd, default_sd); + + if (default_sd) + FIXME("Returning a default security descriptor is not implemented.\n"); + + return HRESULT_FROM_WIN32(GetNamedSecurityInfoW(info->path, SE_FILE_OBJECT, + mask, NULL, NULL, NULL, NULL, sd)); +} + +static HRESULT WINAPI security_info_SetSecurity(ISecurityInformation *iface, + SECURITY_INFORMATION mask, PSECURITY_DESCRIPTOR sd) +{ + struct security_info *info = impl_from_ISecurityInformation(iface); + BOOL present, defaulted; + PSID owner, group; + ACL *dacl, *sacl; + + TRACE("iface %p, mask %#x, sd %p.\n", iface, mask, sd); + + if (!GetSecurityDescriptorOwner(sd, &owner, &defaulted)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (!GetSecurityDescriptorGroup(sd, &group, &defaulted)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (!GetSecurityDescriptorDacl(sd, &present, &dacl, &defaulted)) + return HRESULT_FROM_WIN32(GetLastError()); + if (!present) dacl = NULL; + + if (!GetSecurityDescriptorSacl(sd, &present, &sacl, &defaulted)) + return HRESULT_FROM_WIN32(GetLastError()); + if (!present) sacl = NULL; + + return HRESULT_FROM_WIN32(SetNamedSecurityInfoW(info->path, SE_FILE_OBJECT, + mask, owner, group, dacl, sacl)); +} + +static HRESULT WINAPI security_info_GetAccessRights(ISecurityInformation *iface, + const GUID *type, DWORD flags, SI_ACCESS **access, ULONG *count, ULONG *default_access ) +{ + struct security_info *info = impl_from_ISecurityInformation(iface); + + TRACE("info %p, type %s, flags %#x, access %p, count %p, default_access %p.\n", + info, debugstr_guid(type), flags, access, count, default_access); + + if (info->directory) + { + *access = (SI_ACCESS *)access_rights_directory; + *count = ARRAY_SIZE(access_rights_directory); + } + else + { + *access = (SI_ACCESS *)access_rights_file; + *count = ARRAY_SIZE(access_rights_file); + } + + *default_access = 0; + return S_OK; +} + +static HRESULT WINAPI security_info_MapGeneric(ISecurityInformation *iface, + const GUID *type, UCHAR *ace_flags, ACCESS_MASK *mask) +{ + GENERIC_MAPPING map = + { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_ALL_ACCESS + }; + + TRACE("iface %p, type %s, ace_flags %p, mask %p.\n", iface, debugstr_guid(type), ace_flags, mask); + + MapGenericMask(mask, &map); + return S_OK; +} + +static HRESULT WINAPI security_info_GetInheritTypes(ISecurityInformation *iface, + SI_INHERIT_TYPE **types, ULONG *count) +{ + FIXME("iface %p, types %p, count %p, stub!\n", iface, types, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI security_info_PropertySheetPageCallback(ISecurityInformation *iface, + HWND hwnd, UINT msg, SI_PAGE_TYPE page) +{ + TRACE("iface %p, hwnd %p, msg %#x, page %#x.\n", iface, hwnd, msg, page); + return S_OK; +} + +static const struct ISecurityInformationVtbl security_info_vtbl = +{ + security_info_QueryInterface, + security_info_AddRef, + security_info_Release, + security_info_GetObjectInformation, + security_info_GetSecurity, + security_info_SetSecurity, + security_info_GetAccessRights, + security_info_MapGeneric, + security_info_GetInheritTypes, + security_info_PropertySheetPageCallback, +}; + +static ISecurityInformation *create_security_info(WCHAR *path, BOOL directory) +{ + struct security_info *security; + DWORD len; + + if (!(security = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*security)))) + return NULL; + + security->ISecurityInformation_iface.lpVtbl = &security_info_vtbl; + security->refcount = 1; + security->directory = directory; + + len = (strlenW(path) + 1) * sizeof(WCHAR); + security->path = HeapAlloc(GetProcessHeap(), 0, len); + if (!security->path) + { + HeapFree(GetProcessHeap(), 0, security); + return NULL; + } + + memcpy(security->path, path, len); + return &security->ISecurityInformation_iface; +} + +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_security_info(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) @@ -697,6 +998,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 92185d637e7..dfbe7d8588b 100644 --- a/dlls/shell32/shresdef.h +++ b/dlls/shell32/shresdef.h @@ -149,6 +149,26 @@ #define IDM_RECYCLEBIN_RESTORE 301 #define IDM_RECYCLEBIN_ERASE 302 +#define IDS_SECURITY_ADD_FILE 400 +#define IDS_SECURITY_ADD_SUBDIRECTORY 401 +#define IDS_SECURITY_ALL_ACCESS 402 +#define IDS_SECURITY_APPEND_DATA 403 +#define IDS_SECURITY_DELETE 404 +#define IDS_SECURITY_DELETE_CHILD 405 +#define IDS_SECURITY_EXECUTE 406 +#define IDS_SECURITY_LIST_DIRECTORY 407 +#define IDS_SECURITY_READ_ATTRIBUTES 408 +#define IDS_SECURITY_READ_CONTROL 409 +#define IDS_SECURITY_READ_DATA 410 +#define IDS_SECURITY_READ_EA 411 +#define IDS_SECURITY_SYNCHRONIZE 412 +#define IDS_SECURITY_TRAVERSE 413 +#define IDS_SECURITY_WRITE_ATTRIBUTES 414 +#define IDS_SECURITY_WRITE_DAC 415 +#define IDS_SECURITY_WRITE_DATA 416 +#define IDS_SECURITY_WRITE_EA 417 +#define IDS_SECURITY_WRITE_OWNER 418 + /* Note: this string is referenced from the registry*/ #define IDS_RECYCLEBIN_FOLDER_NAME 8964 -- 2.30.1