/* * s a f e r u n . c p p * * Purpose: * Athena's version of shdocvw's saferun dialog * * Owner: * brettm. * * History: * Created: March 1997 * * Copyright (C) Microsoft Corp. 1996. */ #include "pch.hxx" #include #include "dllmain.h" #include "resource.h" #include "util.h" #include "attrun.h" #include "saferun.h" #include "strconst.h" #include #include "demand.h" #include "shlwapip.h" /* * c o n s t a n t s */ #define FTA_OpenIsSafe 0x00010000 // 17. the file class's open verb may be safely invoked for downloaded files #define FTA_NoEdit 0x00000008 // 4. no editing of file type /* * t y p e d e f s */ typedef struct SAFEOPENPARAM_tag { LPCWSTR lpszFileName; LPCWSTR lpszFileClass; LPCWSTR lpszExt; HRESULT hr; } SAFEOPENPARAM, *LPSAFEOPENPARAM; /* * p r o t o t y p e s */ LRESULT SetRegKeyValue(HKEY hkeyParent, PCWSTR pcszSubKey, LPCWSTR pcszValue, DWORD dwType, const BYTE *pcbyte, DWORD dwcb); LRESULT GetRegKeyValue(HKEY hkeyParent, PCWSTR pcszSubKey, PCWSTR pcszValue, PDWORD pdwValueType, PBYTE pbyteBuf, PDWORD pdwcbBufLen); BOOL RememberFileIsSafeToOpen(LPCWSTR szFileClass); BOOL FIsExtBad(LPCWSTR lpszExt); HRESULT SafeOpenDialog(HWND hwnd, LPSAFEOPENPARAM pSafeOpen); INT_PTR CALLBACK SafeOpenDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); /* * return codes: * S_OPENFILE : file should be opened * S_SAVEFILE : file should be saved * * errors: * E_FAIL, E_INVALIDARG, hrUserCancel * */ HRESULT IsSafeToRun(HWND hwnd, LPCWSTR lpszFileName, BOOL fPrompt) { BOOL fSafe; DWORD dwValueType, dwEditFlags; ULONG cb; WCHAR *szExt, szFileClass[MAX_PATH]; SAFEOPENPARAM rSafeOpen={0}; if (lpszFileName == NULL || *lpszFileName == NULL) return E_INVALIDARG; *szFileClass = 0; szExt = PathFindExtensionW(lpszFileName); if (*szExt) { cb = sizeof(szFileClass); RegQueryValueWrapW(HKEY_CLASSES_ROOT, szExt, szFileClass, (LONG*)&cb); } cb = sizeof(dwEditFlags); // $34489. Make HTML files ALWAYS unsafe if (PathIsHTMLFileW(lpszFileName)) fSafe = FALSE; else fSafe = ((GetRegKeyValue(HKEY_CLASSES_ROOT, szFileClass, L"EditFlags", &dwValueType, (PBYTE)&dwEditFlags, &cb) == ERROR_SUCCESS) && (dwValueType == REG_BINARY || dwValueType == REG_DWORD) && (dwEditFlags & FTA_OpenIsSafe)) && !FIsExtBad(szExt); rSafeOpen.lpszFileName = lpszFileName; rSafeOpen.lpszFileClass = szFileClass; rSafeOpen.lpszExt = szExt; return fSafe ? MIMEEDIT_S_OPENFILE : (fPrompt ? SafeOpenDialog(hwnd, &rSafeOpen) : MIMEEDIT_E_USERCANCEL); } HRESULT SafeOpenDialog(HWND hwnd, LPSAFEOPENPARAM pSafeOpen) { pSafeOpen->hr = E_FAIL; // incase we fail DialogBoxParamWrapW(g_hLocRes, MAKEINTRESOURCEW(iddSafeOpen), hwnd, SafeOpenDlgProc, (LPARAM)pSafeOpen); return pSafeOpen->hr; } #define MAXDISPLAYNAMELEN 64 INT_PTR CALLBACK SafeOpenDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LPSAFEOPENPARAM pSafeOpen; switch(msg) { case WM_INITDIALOG: { Assert (lParam); SetWindowLongPtr(hwnd, DWLP_USER, lParam); pSafeOpen = (LPSAFEOPENPARAM)lParam; // if an UNSAFE extension type, don't allow user to set edit flags if (FIsExtBad(pSafeOpen->lpszExt)) EnableWindow(GetDlgItem(hwnd, IDC_SAFEOPEN_ALWAYS), FALSE); CheckDlgButton(hwnd, IDC_SAFEOPEN_ALWAYS, TRUE); CheckDlgButton(hwnd, IDC_SAFEOPEN_AUTOSAVE, TRUE); WCHAR szBuf[32]; WCHAR szBuf2[MAX_PATH+32]; // ok with MAX_PATH WCHAR szBuf3[MAX_PATH+32]; // ok with MAX_PATH int length = 0; StrCpyNW(szBuf3, pSafeOpen->lpszFileName, ARRAYSIZE(szBuf3)); PathStripPathW(szBuf3); length = lstrlenW(szBuf3); if (length > MAXDISPLAYNAMELEN) { WCHAR *szExt; szExt = PathFindExtensionW(pSafeOpen->lpszFileName); if (*szExt) { int cExt = lstrlenW(szExt); if (cExt < MAXDISPLAYNAMELEN-3) { PathCompactPathExW(szBuf2, szBuf3, MAXDISPLAYNAMELEN-cExt, 0); StrCatBuffW(szBuf2, szExt, ARRAYSIZE(szBuf2)); } else PathCompactPathExW(szBuf2, szBuf3, MAXDISPLAYNAMELEN, 0); } else { PathCompactPathExW(szBuf2, szBuf3, MAXDISPLAYNAMELEN, 0); } StrCpyNW(szBuf3, szBuf2, ARRAYSIZE(szBuf3)); } GetDlgItemTextWrapW(hwnd, IDC_SAFEOPEN_EXPL, szBuf, ARRAYSIZE(szBuf)); wnsprintfW(szBuf2, ARRAYSIZE(szBuf2), szBuf, szBuf3); SetDlgItemTextWrapW(hwnd, IDC_SAFEOPEN_EXPL, szBuf2); CenterDialog(hwnd); } return TRUE; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: pSafeOpen = (LPSAFEOPENPARAM)GetWindowLongPtr(hwnd, DWLP_USER); if (!IsDlgButtonChecked(hwnd, IDC_SAFEOPEN_ALWAYS)) RememberFileIsSafeToOpen(pSafeOpen->lpszFileClass); pSafeOpen->hr = IsDlgButtonChecked(hwnd, IDC_SAFEOPEN_AUTOSAVE) ? MIMEEDIT_S_SAVEFILE : MIMEEDIT_S_OPENFILE; EndDialog(hwnd, IDOK); break; case IDCANCEL: pSafeOpen = (LPSAFEOPENPARAM)GetWindowLongPtr(hwnd, DWLP_USER); pSafeOpen->hr = MIMEEDIT_E_USERCANCEL; EndDialog(hwnd, IDCANCEL); break; } break; } return FALSE; } LRESULT GetRegKeyValue(HKEY hkeyParent, PCWSTR pcszSubKey, PCWSTR pcszValue, PDWORD pdwValueType, PBYTE pbyteBuf, PDWORD pdwcbBufLen) { LONG lResult; HKEY hkeySubKey; if (GetSystemMetrics(SM_CLEANBOOT)) return ERROR_GEN_FAILURE; lResult = RegOpenKeyExWrapW(hkeyParent, pcszSubKey, 0, KEY_QUERY_VALUE, &hkeySubKey); if (lResult == ERROR_SUCCESS) { LONG lResultClose; lResult = RegQueryValueExWrapW(hkeySubKey, pcszValue, NULL, pdwValueType, pbyteBuf, pdwcbBufLen); lResultClose = RegCloseKey(hkeySubKey); if (lResult == ERROR_SUCCESS) lResult = lResultClose; } return(lResult); } LRESULT SetRegKeyValue(HKEY hkeyParent, PCWSTR pcszSubKey, LPCWSTR pcszValue, DWORD dwType, const BYTE *pcbyte, DWORD dwcb) { LONG lResult; HKEY hkeySubKey; lResult = RegCreateKeyExWrapW(hkeyParent, pcszSubKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkeySubKey, NULL); if (lResult == ERROR_SUCCESS) { LONG lResultClose; lResult = RegSetValueExWrapW(hkeySubKey, pcszValue, 0, dwType, pcbyte, dwcb); lResultClose = RegCloseKey(hkeySubKey); if (lResult == ERROR_SUCCESS) lResult = lResultClose; } return(lResult); } BOOL RememberFileIsSafeToOpen(LPCWSTR szFileClass) { DWORD dwValueType, dwEditFlags; ULONG cb = sizeof(dwEditFlags); if (szFileClass==NULL || *szFileClass == NULL) return FALSE; if (GetRegKeyValue(HKEY_CLASSES_ROOT, szFileClass, L"EditFlags", &dwValueType, (PBYTE)&dwEditFlags, &cb) == ERROR_SUCCESS && (dwValueType == REG_BINARY || dwValueType == REG_DWORD)) { dwEditFlags &= ~FTA_NoEdit; dwEditFlags |= FTA_OpenIsSafe; } else { dwEditFlags = FTA_OpenIsSafe; } return (SetRegKeyValue(HKEY_CLASSES_ROOT, szFileClass, L"EditFlags", REG_BINARY, (BYTE*)&dwEditFlags, sizeof(dwEditFlags)) == ERROR_SUCCESS); } // Keep in sync with c_arszUnsafeExts in shell\shdocvw\download.cpp // @todo [NeilBren, TonyC] Move this to the registry and have IE and OE share it static const LPWSTR szBadExt[] = { L".exe", L".com", L".bat", L".lnk", L".url", L".cmd", L".inf", L".reg", L".isp", L".bas", L".pcd", L".mst", L".pif", L".scr", L".hlp", L".chm", L".hta", L".asp", L".js", L".jse", L".vbs", L".vbe", L".ws", L".wsh", L".msi", L".ade", L".adp", L".crt", L".ins", L".mdb", L".mde", L".msc", L".msp", L".sct", L".shb", L".vb", L".wsc", L".wsf", L".cpl", L".shs", L".vsd", L".vst", L".vss", L".vsw", L".its", L".tmp", L".mdw", L".mdt", L".ops", L".mda", L".mdz", L".prf", L".scf", L".ksh", L".csh", L".app", L".fxp", L".prg", L".htm", L".html",L".vsmacros" }; BOOL FIsExtBad(LPCWSTR lpszExt) { if (lpszExt == NULL || *lpszExt == NULL) return TRUE; for (int i=0; i