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
This commit is contained in:
Katayama Hirofumi MZ 2020-02-12 09:18:24 +09:00 committed by GitHub
parent 0a7a747d87
commit bc1519dd87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 219 additions and 10 deletions

View file

@ -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;
}

View file

@ -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()
};

View file

@ -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:

View file

@ -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()
};

View file

@ -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);

View file

@ -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);

View file

@ -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
*/