https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bc1519dd87a96d37a1b9c64efb43901d5c386872

commit bc1519dd87a96d37a1b9c64efb43901d5c386872
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Wed Feb 12 09:18:24 2020 +0900
Commit:     GitHub <[email protected]>
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%29.aspx
     //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
  */

Reply via email to