https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bc1519dd87a96d37a1b9c…
commit bc1519dd87a96d37a1b9c64efb43901d5c386872
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Wed Feb 12 09:18:24 2020 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Wed Feb 12 09:18:24 2020 +0900
Shell Folders: Reject invalid characters (#2328)
Reject invalid input filename characters by using shell32!SHLimitInputEdit function
and IItemNameLimits interface. Improve SHLimitInputEdit to sanitize paste.
CORE-11701
---
dll/win32/shell32/CDefView.cpp | 4 +
dll/win32/shell32/folders/CDesktopFolder.h | 26 ++++++-
dll/win32/shell32/folders/CFSFolder.h | 26 ++++++-
dll/win32/shell32/folders/CMyDocsFolder.h | 26 ++++++-
dll/win32/shell32/shellmenu/CMergedFolder.h | 24 ++++++
dll/win32/shell32/wine/shellord.c | 110 ++++++++++++++++++++++++++--
sdk/include/reactos/undocshell.h | 13 ++++
7 files changed, 219 insertions(+), 10 deletions(-)
diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp
index 608ada85bf4..2bbf523fbe7 100644
--- a/dll/win32/shell32/CDefView.cpp
+++ b/dll/win32/shell32/CDefView.cpp
@@ -1989,9 +1989,13 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam,
BOOL &bHandl
m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
if (SFGAO_CANRENAME & dwAttr)
{
+ HWND hEdit =
reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
+ SHLimitInputEdit(hEdit, m_pSFParent);
+
m_isEditing = TRUE;
return FALSE;
}
+
return TRUE;
}
diff --git a/dll/win32/shell32/folders/CDesktopFolder.h
b/dll/win32/shell32/folders/CDesktopFolder.h
index 3ac844323aa..eddeb8043bd 100644
--- a/dll/win32/shell32/folders/CDesktopFolder.h
+++ b/dll/win32/shell32/folders/CDesktopFolder.h
@@ -28,7 +28,8 @@ class CDesktopFolder :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IShellFolder2,
public IPersistFolder2,
- public IContextMenuCB
+ public IContextMenuCB,
+ public IItemNameLimits
{
private:
/* both paths are parsible from the desktop */
@@ -79,6 +80,28 @@ class CDesktopFolder :
// IContextMenuCB
virtual HRESULT WINAPI CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject
*pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ /*** IItemNameLimits methods ***/
+
+ STDMETHODIMP
+ GetMaxLength(LPCWSTR pszName, int *piMaxNameLen)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP
+ GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars)
+ {
+ if (ppwszValidChars)
+ {
+ *ppwszValidChars = NULL;
+ }
+ if (ppwszInvalidChars)
+ {
+ SHStrDupW(INVALID_FILETITLE_CHARACTERSW, ppwszInvalidChars);
+ }
+ return S_OK;
+ }
+
DECLARE_REGISTRY_RESOURCEID(IDR_SHELLDESKTOP)
DECLARE_CENTRAL_INSTANCE_NOT_AGGREGATABLE(CDesktopFolder)
@@ -90,6 +113,7 @@ class CDesktopFolder :
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+ COM_INTERFACE_ENTRY_IID(IID_IItemNameLimits, IItemNameLimits)
END_COM_MAP()
};
diff --git a/dll/win32/shell32/folders/CFSFolder.h
b/dll/win32/shell32/folders/CFSFolder.h
index 6c6f055a3f8..c5f1d1bf2ae 100644
--- a/dll/win32/shell32/folders/CFSFolder.h
+++ b/dll/win32/shell32/folders/CFSFolder.h
@@ -29,7 +29,8 @@ class CFSFolder :
public IShellFolder2,
public IPersistFolder3,
public IContextMenuCB,
- public IShellFolderViewCB
+ public IShellFolderViewCB,
+ public IItemNameLimits
{
private:
const CLSID *m_pclsid;
@@ -88,6 +89,28 @@ class CFSFolder :
// IShellFolderViewCB
virtual HRESULT WINAPI MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ /*** IItemNameLimits methods ***/
+
+ STDMETHODIMP
+ GetMaxLength(LPCWSTR pszName, int *piMaxNameLen)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP
+ GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars)
+ {
+ if (ppwszValidChars)
+ {
+ *ppwszValidChars = NULL;
+ }
+ if (ppwszInvalidChars)
+ {
+ SHStrDupW(INVALID_FILETITLE_CHARACTERSW, ppwszInvalidChars);
+ }
+ return S_OK;
+ }
+
DECLARE_REGISTRY_RESOURCEID(IDR_SHELLFSFOLDER)
DECLARE_NOT_AGGREGATABLE(CFSFolder)
@@ -101,6 +124,7 @@ class CFSFolder :
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder3, IPersistFolder3)
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB)
+ COM_INTERFACE_ENTRY_IID(IID_IItemNameLimits, IItemNameLimits)
END_COM_MAP()
protected:
diff --git a/dll/win32/shell32/folders/CMyDocsFolder.h
b/dll/win32/shell32/folders/CMyDocsFolder.h
index 9f89621fae1..6bed840fcbc 100644
--- a/dll/win32/shell32/folders/CMyDocsFolder.h
+++ b/dll/win32/shell32/folders/CMyDocsFolder.h
@@ -26,7 +26,8 @@ class CMyDocsFolder :
public CComCoClass<CMyDocsFolder, &CLSID_MyDocuments>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IShellFolder2,
- public IPersistFolder2
+ public IPersistFolder2,
+ public IItemNameLimits
{
private:
CComPtr<IShellFolder2> m_pisfInner;
@@ -65,6 +66,28 @@ class CMyDocsFolder :
// IPersistFolder2
virtual HRESULT WINAPI GetCurFolder(PIDLIST_ABSOLUTE * pidl);
+ /*** IItemNameLimits methods ***/
+
+ STDMETHODIMP
+ GetMaxLength(LPCWSTR pszName, int *piMaxNameLen)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP
+ GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars)
+ {
+ if (ppwszValidChars)
+ {
+ *ppwszValidChars = NULL;
+ }
+ if (ppwszInvalidChars)
+ {
+ SHStrDupW(INVALID_FILETITLE_CHARACTERSW, ppwszInvalidChars);
+ }
+ return S_OK;
+ }
+
DECLARE_REGISTRY_RESOURCEID(IDR_MYDOCUMENTS)
DECLARE_NOT_AGGREGATABLE(CMyDocsFolder)
@@ -76,6 +99,7 @@ class CMyDocsFolder :
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+ COM_INTERFACE_ENTRY_IID(IID_IItemNameLimits, IItemNameLimits)
END_COM_MAP()
};
diff --git a/dll/win32/shell32/shellmenu/CMergedFolder.h
b/dll/win32/shell32/shellmenu/CMergedFolder.h
index 4bc9ee20278..e76fc98c098 100644
--- a/dll/win32/shell32/shellmenu/CMergedFolder.h
+++ b/dll/win32/shell32/shellmenu/CMergedFolder.h
@@ -50,6 +50,7 @@ class CMergedFolder :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IShellFolder2,
public IPersistFolder2,
+ public IItemNameLimits,
public IAugmentedShellFolder3 // -- undocumented
//public IShellService, // DEPRECATED IE4 interface:
https://msdn.microsoft.com/en-us/library/windows/desktop/bb774870%28v=vs.85…
//public ITranslateShellChangeNotify,// -- undocumented
@@ -84,6 +85,7 @@ public:
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder)
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
+ COM_INTERFACE_ENTRY_IID(IID_IItemNameLimits, IItemNameLimits)
COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder, IAugmentedShellFolder)
COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder2, IAugmentedShellFolder2)
COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder3, IAugmentedShellFolder3)
@@ -196,6 +198,28 @@ public:
// IPersistFolder2
virtual HRESULT STDMETHODCALLTYPE GetCurFolder(PIDLIST_ABSOLUTE * pidl);
+ /*** IItemNameLimits methods ***/
+
+ STDMETHODIMP
+ GetMaxLength(LPCWSTR pszName, int *piMaxNameLen)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP
+ GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars)
+ {
+ if (ppwszValidChars)
+ {
+ *ppwszValidChars = NULL;
+ }
+ if (ppwszInvalidChars)
+ {
+ SHStrDupW(INVALID_FILETITLE_CHARACTERSW, ppwszInvalidChars);
+ }
+ return S_OK;
+ }
+
// IAugmentedShellFolder2
virtual HRESULT STDMETHODCALLTYPE AddNameSpace(LPGUID lpGuid, IShellFolder * psf,
LPCITEMIDLIST pcidl, ULONG dwUnknown);
virtual HRESULT STDMETHODCALLTYPE GetNameSpaceID(LPCITEMIDLIST pcidl, LPGUID
lpGuid);
diff --git a/dll/win32/shell32/wine/shellord.c b/dll/win32/shell32/wine/shellord.c
index 404ecc2a98b..9b4c6ab9eba 100644
--- a/dll/win32/shell32/wine/shellord.c
+++ b/dll/win32/shell32/wine/shellord.c
@@ -2179,10 +2179,88 @@ UxSubclassInfo_Destroy(UxSubclassInfo *pInfo)
HeapFree(GetProcessHeap(), 0, pInfo);
}
+static BOOL
+DoSanitizeText(LPWSTR pszSanitized, LPCWSTR pszInvalidChars, LPCWSTR pszValidChars)
+{
+ LPWSTR pch1, pch2;
+ BOOL bFound = FALSE;
+
+ for (pch1 = pch2 = pszSanitized; *pch1; ++pch1)
+ {
+ if (pszInvalidChars)
+ {
+ if (wcschr(pszInvalidChars, *pch1) != NULL)
+ {
+ bFound = TRUE;
+ continue;
+ }
+ }
+ else if (pszValidChars)
+ {
+ if (wcschr(pszValidChars, *pch1) == NULL)
+ {
+ bFound = TRUE;
+ continue;
+ }
+ }
+
+ *pch2 = *pch1;
+ ++pch2;
+ }
+ *pch2 = 0;
+
+ return bFound;
+}
+
+static void
+DoSanitizeClipboard(HWND hwnd, UxSubclassInfo *pInfo)
+{
+ HGLOBAL hData;
+ LPWSTR pszText, pszSanitized;
+ DWORD cbData;
+
+ if (GetWindowLongPtrW(hwnd, GWL_STYLE) & ES_READONLY)
+ return;
+ if (!OpenClipboard(hwnd))
+ return;
+
+ hData = GetClipboardData(CF_UNICODETEXT);
+ pszText = GlobalLock(hData);
+ if (!pszText)
+ {
+ CloseClipboard();
+ return;
+ }
+ SHStrDupW(pszText, &pszSanitized);
+ GlobalUnlock(hData);
+
+ if (pszSanitized &&
+ DoSanitizeText(pszSanitized, pInfo->pwszInvalidChars,
pInfo->pwszValidChars))
+ {
+ MessageBeep(0xFFFFFFFF);
+
+ /* Update clipboard text */
+ cbData = (lstrlenW(pszSanitized) + 1) * sizeof(WCHAR);
+ hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, cbData);
+ pszText = GlobalLock(hData);
+ if (pszText)
+ {
+ CopyMemory(pszText, pszSanitized, cbData);
+ GlobalUnlock(hData);
+
+ SetClipboardData(CF_UNICODETEXT, hData);
+ }
+ }
+
+ CoTaskMemFree(pszSanitized);
+ CloseClipboard();
+}
+
static LRESULT CALLBACK
LimitEditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WNDPROC fnWndProc;
+ WCHAR wch;
UxSubclassInfo *pInfo = GetPropW(hwnd, L"UxSubclassInfo");
if (!pInfo)
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
@@ -2191,8 +2269,22 @@ LimitEditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
switch (uMsg)
{
+ case WM_KEYDOWN:
+ if (GetKeyState(VK_SHIFT) < 0 && wParam == VK_INSERT)
+ DoSanitizeClipboard(hwnd, pInfo);
+ else if (GetKeyState(VK_CONTROL) < 0 && wParam == L'V')
+ DoSanitizeClipboard(hwnd, pInfo);
+
+ return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
+
+ case WM_PASTE:
+ DoSanitizeClipboard(hwnd, pInfo);
+ return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
+
case WM_CHAR:
- {
+ if (GetKeyState(VK_CONTROL) < 0 && wParam == L'V')
+ break;
+
if (pInfo->pwszInvalidChars)
{
if (wcschr(pInfo->pwszInvalidChars, (WCHAR)wParam) != NULL)
@@ -2210,11 +2302,18 @@ LimitEditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
}
}
return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
- }
+
+ case WM_UNICHAR:
+ if (wParam == UNICODE_NOCHAR)
+ return TRUE;
+
+ /* FALL THROUGH */
case WM_IME_CHAR:
- {
- WCHAR wch = (WCHAR)wParam;
+ wch = (WCHAR)wParam;
+ if (GetKeyState(VK_CONTROL) < 0 && wch == L'V')
+ break;
+
if (!IsWindowUnicode(hwnd) && HIBYTE(wch) != 0)
{
CHAR data[] = {HIBYTE(wch), LOBYTE(wch)};
@@ -2238,13 +2337,10 @@ LimitEditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
}
}
return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
- }
case WM_NCDESTROY:
- {
UxSubclassInfo_Destroy(pInfo);
return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
- }
default:
return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam);
diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h
index 1757a055734..1927bf26015 100644
--- a/sdk/include/reactos/undocshell.h
+++ b/sdk/include/reactos/undocshell.h
@@ -697,6 +697,19 @@ IStream* WINAPI SHGetViewStream(LPCITEMIDLIST, DWORD, LPCTSTR,
LPCTSTR, LPCTSTR)
EXTERN_C HRESULT WINAPI SHCreateSessionKey(REGSAM samDesired, PHKEY phKey);
+/*****************************************************************************
+ * INVALID_FILETITLE_CHARACTERS
+ */
+
+#define INVALID_FILETITLE_CHARACTERSA "\\/:*?\"<>|"
+#define INVALID_FILETITLE_CHARACTERSW L"\\/:*?\"<>|"
+
+#ifdef UNICODE
+ #define INVALID_FILETITLE_CHARACTERS INVALID_FILETITLE_CHARACTERSW
+#else
+ #define INVALID_FILETITLE_CHARACTERS INVALID_FILETITLE_CHARACTERSA
+#endif
+
/*****************************************************************************
* Shell Link
*/