/**
* This code is by OShah. all code will have the following licence.
* Copyright Shexec32. All code bears the following licence:
**/
/**
* Copyright Shexec32 2004-2005. All rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
**/
#include "../FilePermsBoxDLL/SecurityCore.h"
#include "FilePermissionsBox.h"
bool g_AddWritability = FALSE; /* Application Setting (set by user). */
int APIENTRY _tWinMain(HINSTANCE hInst, HINSTANCE, LPTSTR lpCmdLine, int nCmdShow)
{/* This program dumps the acls for the service. */
#ifdef _DEBUG
::_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF |
_CRTDBG_ALLOC_MEM_DF | ::_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG));
#endif /* _DEBUG. This detects memory leaks */
intptr_t Result = 0; /* main will return this result. */
try {
std::basic_string<TCHAR> sCmdLine(lpCmdLine);
CoAutoInitializer autoCom;
::InitCommonControls(); /* Bring in Themed common controls */
/* Our command line needs to be a case insensitive string. */
if(CheckVersion() != TRUE)
{/* Win2k warning (and other misbehaving compiler warning). */
_bstr_t Win98Hack = _T("This program requires Windows 2000 or later. ")
_T("It may not work on your system. Do you want to continue?");
/* WORKAROUND: If OleAut32 isn't loaded, Win9x will crash due to delay load in DllMain(DLL_DETACH) */
Result = ::MessageBox(NULL, static_cast<const TCHAR *>(Win98Hack), _T("FilePermBox"), MB_YESNO | MB_DEFBUTTON2);
if(Result != IDYES)
{
return 0;
}
}
::SetLastError(ERROR_SUCCESS);
Result = ::ParseCmdLine(sCmdLine); /* Send the command line off to the separate procedure */
if(Result != 2)/* If result isn't 2, then we've done what we've needed to do, so quit. */
return int(Result);
{/* Otherwise, start the program */
MSG msg = {0};
HWND hWndDlg = ::CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL,
FileSelectBox, reinterpret_cast<LPARAM>(&sCmdLine));
if (hWndDlg == NULL)
throw STD(_T("Error creating dialog box"));
HACCEL hAccelTable = ::LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_ACCELERATOR1));
if(hAccelTable == NULL)
throw STD(_T("Error creating keyboard shortcuts"));
::ShowWindow(hWndDlg, nCmdShow);
::UpdateWindow(hWndDlg);
/* Now for the Dialog Message Loop. */
while (::GetMessage(&msg, NULL, 0, 0) > 0)
{
if(!::TranslateAccelerator(hWndDlg,hAccelTable,&msg))
{
if (hWndDlg == NULL || ::IsDialogMessage(hWndDlg, &msg) == FALSE)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
Result = msg.wParam;
if(Result == 2)
{/* 2 indicates we caught an exception. */
throw STD(_T("An unknown error occurred with program"));
}
}
} catch (const std::basic_string<TCHAR> &Tout) {/* One of our exceptions was caught. Complete the program */
std::basic_stringstream<TCHAR> TError;
TError << Tout << _T("\nThe Last Win32 Error is ") << ::GetLastError() << _T(": ") <<
static_cast<const TCHAR *>(GetLastErrorText(::GetLastError()));
::MessageBox(NULL, TError.str().c_str(), _T("Problem Detected - FilePermsBox"), MB_OK | MB_ICONERROR);
}
#if !defined (_DEBUG)
catch (...) {
/** some other exception occurred, complete the program. Don't catch this in debug builds,
* Let the debugger handle it.
**/
std::basic_stringstream<TCHAR> TError;
TError << _T("An error occurred in the program. FilePermsBox could not determine the nature of the problem.\n")
<< _T("The Last Win32 Error is ") << ::GetLastError() << _T(": ") <<
static_cast<const TCHAR *>(GetLastErrorText(::GetLastError()));
::MessageBox(NULL, TError.str().c_str(), _T("Problem Detected - FilePermsBox"), MB_OK | MB_ICONERROR);
}
#endif /* _DEBUG. Only in release builds do we catch all. */
return 0;
}
INT_PTR CALLBACK FileSelectBox(HWND TheirhWnd, UINT message, WPARAM wParam, LPARAM lParam)
{/** This frontend consists of a File input box (with browse button), where the user enters their file.
* When the user presses OK, out pops the security tab for that file.
**/
try {/* for catch (...) */
switch (message)
{
case WM_INITDIALOG:
{/* We'll need to apply resize properties. */
/* Load the application icon into this dialog box. */
HANDLE hIcon = ::LoadImage(::GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1),
IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
::SetClassLongPtr(TheirhWnd, GCLP_HICON, LONG_PTR2(hIcon));
if( !::IsBadReadPtr(reinterpret_cast<const void *>(lParam), sizeof(std::basic_string<TCHAR>)) )
{/* lParam contains a pointer to sCmdLine in main(). Put sCmdLine into the edit box. */
std::basic_string<TCHAR> *sCmdLinePtr = reinterpret_cast<std::basic_string<TCHAR> *>(lParam);
::SetDlgItemText(TheirhWnd, IDC_EDIT1, sCmdLinePtr->c_str());
}
/* Put in the text. */
::SetDlgItemText(TheirhWnd, IDC_TITLE,
_T("Enter the name of a filesystem object to view its security descriptor and permissions."));
::SetWindowText(TheirhWnd, _T("FilePermsBox - Filename Required"));
/* Default to read only. */
::CheckDlgButton(TheirhWnd, IDC_CHECK1, !g_AddWritability);
::DragAcceptFiles(TheirhWnd, TRUE);
{/* Finally, send a WM_SIZE message */
RECT RectDlg = {0};
::GetWindowRect(TheirhWnd, &RectDlg);
::SetWindowPos(TheirhWnd, NULL, 0, 0, RectDlg.right - RectDlg.left + 1, 200, SWP_NOZORDER | SWP_NOMOVE);
}
return TRUE;
}
case WM_DROPFILES:
{/* WM_DROPFILES - The user has dropped a file into our dialog. */
int len = ::DragQueryFile(reinterpret_cast<HDROP>(wParam), 0, NULL, 0);
if(len == 0) return FALSE;
/* Get the required size and allocate a buffer of that size. */
sized_array<TCHAR> sFName ( len + 1 );
::DragQueryFile(reinterpret_cast<HDROP>(wParam), 0, sFName.get(), len + 1);
/* Just the first file. */
::DragFinish(reinterpret_cast<HDROP>(wParam));
/* and put the first file into IDC_EDIT1 */
::SetDlgItemText(TheirhWnd, IDC_EDIT1, sFName.get());
return FALSE;
}
case WM_GETMINMAXINFO:
{/* The Window needs to be 300x160 */
MINMAXINFO *MinMaxInfo = reinterpret_cast<MINMAXINFO *>(lParam);
MinMaxInfo->ptMinTrackSize.x = 300;
MinMaxInfo->ptMinTrackSize.y = 160;
MinMaxInfo->ptMaxTrackSize.y = 160;
return TRUE;
}
case WM_SIZE:
{/* WM_SIZE. */
const int space = 7;
RECT RectDlg = {0}, RectCtl = {0};
int x = RectCtl.left;
HDWP hdwp = ::BeginDeferWindowPos(7); /* 7's a bit of an underflow. There's really only about 5. */
{/* Get The Client area of the Window. */
::GetWindowRect(TheirhWnd, &RectDlg);
::MapWindowPoints(NULL, TheirhWnd, (LPPOINT)&RectDlg, sizeof(RECT) / sizeof(POINT));
RectDlg.left += space;
RectDlg.top += space;
RectDlg.bottom -= space;
RectDlg.right -= space;
/* Resize IDC_TITLE to right of RectDlg. */
::GetWindowRect(::GetDlgItem(TheirhWnd, IDC_TITLE), &RectCtl);
::MapWindowPoints(NULL, TheirhWnd, (LPPOINT)&RectCtl, sizeof(RECT) / sizeof(POINT));
RectCtl.left = space;
RectCtl.right = RectDlg.right - RectDlg.left - RectCtl.left;
::DeferWindowPos(hdwp, ::GetDlgItem(TheirhWnd, IDC_TITLE), NULL, RectCtl.left, RectCtl.top,
RectCtl.right, RectCtl.bottom - RectCtl.top, SWP_NOCOPYBITS | SWP_NOZORDER);
/* Move IDC_BUTTON1 to right of window (retain size). */
::GetWindowRect(::GetDlgItem(TheirhWnd, IDC_BUTTON1), &RectCtl);
::MapWindowPoints(NULL, TheirhWnd, (LPPOINT)&RectCtl, sizeof(RECT) / sizeof(POINT));
RectCtl.left = RectDlg.right - RectCtl.right + RectCtl.left - space;
::DeferWindowPos(hdwp, ::GetDlgItem(TheirhWnd, IDC_BUTTON1),
NULL, RectCtl.left, RectCtl.top, 0, 0, SWP_NOSIZE | SWP_NOCOPYBITS | SWP_NOZORDER);
/* Make IDC_EDIT1 fill up the rest of the space. */
x = RectCtl.left - space;
::GetWindowRect(::GetDlgItem(TheirhWnd, IDC_EDIT1), &RectCtl);
::MapWindowPoints(NULL, TheirhWnd, (LPPOINT)&RectCtl, sizeof(RECT) / sizeof(POINT));
RectCtl.left = space;
RectCtl.right = x - RectDlg.left - RectCtl.left;
::DeferWindowPos(hdwp, ::GetDlgItem(TheirhWnd, IDC_EDIT1), NULL, RectCtl.left, RectCtl.top,
RectCtl.right, RectCtl.bottom - RectCtl.top, SWP_NOCOPYBITS | SWP_NOZORDER);
/* Move IDCANCEL to bottom right of window. */
::GetWindowRect(::GetDlgItem(TheirhWnd, IDOK), &RectCtl);
::MapWindowPoints(NULL, TheirhWnd, (LPPOINT)&RectCtl, sizeof(RECT) / sizeof(POINT));
RectCtl.left = RectDlg.right - RectCtl.right + RectCtl.left - space;
RectCtl.top = RectDlg.bottom - RectCtl.bottom + RectCtl.top - space;
::DeferWindowPos(hdwp, ::GetDlgItem(TheirhWnd, IDOK),
NULL, RectCtl.left, RectCtl.top, 0, 0, SWP_NOSIZE | SWP_NOCOPYBITS | SWP_NOZORDER);
x = RectCtl.left;
/* Move IDC_ABOUT beside IDC_BUTTON1 (to the left). */
::GetWindowRect(::GetDlgItem(TheirhWnd, IDC_ABOUT), &RectCtl);
::MapWindowPoints(NULL, TheirhWnd, (LPPOINT)&RectCtl, sizeof(RECT) / sizeof(POINT));
RectCtl.left = x - RectCtl.right + RectCtl.left - space;
RectCtl.top = RectDlg.bottom - RectCtl.bottom + RectCtl.top - space;
::DeferWindowPos(hdwp, ::GetDlgItem(TheirhWnd, IDC_ABOUT),
NULL, RectCtl.left, RectCtl.top, 0, 0, SWP_NOSIZE | SWP_NOCOPYBITS | SWP_NOZORDER);
/* IDC_COMBO1 Needs to be offset 10 pixels to the right. */
x = RectCtl.left;
::GetWindowRect(::GetDlgItem(TheirhWnd, IDC_CHECK1), &RectCtl);
::MapWindowPoints(NULL, TheirhWnd, (LPPOINT)&RectCtl, sizeof(RECT) / sizeof(POINT));
RectCtl.left = space + 10;
RectCtl.right = x - RectCtl.left;
::DeferWindowPos(hdwp, ::GetDlgItem(TheirhWnd, IDC_CHECK1), NULL, RectCtl.left, RectCtl.top,
RectCtl.right, RectCtl.bottom - RectCtl.top, SWP_NOCOPYBITS | SWP_NOZORDER);
}
/* Now update the window */
::EndDeferWindowPos(hdwp);
::InvalidateRgn(TheirhWnd, NULL, FALSE);
::UpdateWindow(TheirhWnd);
return TRUE;
}
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDC_ABOUT:
{
ShowAbout(TheirhWnd);
return FALSE;
}
case IDOK :
{
/* [QueryServiceConfig] Get The name of the service. */
int len = 0;
len = 1 + ::GetWindowTextLength(::GetDlgItem(TheirhWnd, IDC_EDIT1));
if(len == 1)
{/* For an empty box, exit the program. */
::PostMessage(TheirhWnd, WM_CLOSE, 0, 0);
return TRUE;
}
::sized_array<TCHAR> lpszString (len);
::GetDlgItemText(TheirhWnd, IDC_EDIT1, lpszString.get(), len);
/* Now that we've retrieved the filename, show it. */
/* Disable all controls */
EnableFrontendControls(TheirhWnd, FALSE);
std::list< const std::basic_string<TCHAR> > FileNamesCollection;
if((len > 3) && (lpszString.get()[len - 2] == _T('*')))
{/* Partial WildCard support. Hand the filename to the external procedure. */
if( lpszString.get()[len - 3] == _T('*') )
{/* "**" means choose dirs. */
lpszString.get()[len - 2] = _T('\0'); /* remove one of the zeros */
WalkDirectory(lpszString.get(), FileNamesCollection, TRUE);
}
else WalkDirectory(lpszString.get(), FileNamesCollection, FALSE);
}
else
{/* No wildcards mean just add the file to FileNamesCollection */
FileNamesCollection.push_back(lpszString.get());
}
if( FileNamesCollection.size() > 0)
{
if(DoSecurityBox(TheirhWnd, SE_FILE_OBJECT, FileNamesCollection, g_AddWritability) != TRUE)
{/* If a problem occurred, exit the program. */
::PostMessage(TheirhWnd, WM_CLOSE, 0, 0);
}
}
/* reenable all controls */
EnableFrontendControls(TheirhWnd, TRUE);
return TRUE;
}
case IDC_BUTTON1:
{/** The browse button was selected, show the common dialog box.
* (note, an explorer control: use it to your advantage).
**/
OPENFILENAME ofn = {0};
sized_array<TCHAR> lpFileNames ( 32768 );/* Big buffer for multi-select. */
if(HandleOfnStruct(TheirhWnd, ofn, lpFileNames.get(), 32 * FILENAME_MAX) == TRUE)
/* Now we can set the file text. */
::SetDlgItemText(TheirhWnd, IDC_EDIT1, lpFileNames.get());
return TRUE;
}
case IDC_CHECK1:
{/* Alter the state of AddWritability. */
g_AddWritability = !g_AddWritability;
::CheckDlgButton(TheirhWnd, IDC_CHECK1, !g_AddWritability);
/* Make sure the checkbox reflects the current state of AddWritability. */
return TRUE;
}
default:
break;
}
break;
}
case WM_CLOSE:
{/* We're a dialog box: We call EndDialog. */
::DestroyWindow(TheirhWnd);
return FALSE;
}
case WM_DESTROY:
{/* If we posted this from the exception, use PostQuitMessage() to send the result code to _tWinMain. */
if(wParam == 2)
{
::PostQuitMessage(2);
}
else
{
::PostQuitMessage(0);
}
break;
}
default:
{
break;
}
}
#ifdef _DEBUG
} catch(const std::basic_string<TCHAR> &) {/* An unknown error occurred, signal the main function. */
#else /* means: if defined NDEBUG */
} catch(...) {
#endif /* _DEBUG */
::PostMessage(TheirhWnd, WM_DESTROY, 2, 0);
} /* two tries */
return FALSE;
}
BOOL EnableFrontendControls(HWND TheirhWnd, BOOL bEnable)
{
BOOL Result = TRUE;
Result = Result & ::EnableWindow(::GetDlgItem(TheirhWnd, IDOK), bEnable);
Result = Result & ::EnableWindow(::GetDlgItem(TheirhWnd, IDC_EDIT1), bEnable);
Result = Result & ::EnableWindow(::GetDlgItem(TheirhWnd, IDC_CHECK1), bEnable);
Result = Result & ::EnableWindow(::GetDlgItem(TheirhWnd, IDC_BUTTON1), bEnable);
Result = Result & ::EnableWindow(::GetDlgItem(TheirhWnd, IDC_ABOUT), bEnable);
return Result;
}
BOOL HandleOfnStruct(HWND TheirhWnd, OPENFILENAME &ofn, LPTSTR FileNames, size_t FileNamesLength)
{/**
* This is ::HandleOfnStruct() taken from the Shexec32 program. The purpose of this function is to
* create the common dialog box. If the browse button was selected, and the user chose his file(s)
* to open, those files would be stored in ofn->lpstrFile.
*
* ofn.lpstrFile only has 32 * FILENAME_MAX characters. There lies the possibility of a buffer overflow here.
* This will occur if ::GetOpenFileName() returns a value greater than 32 * FILENAME_MAX characters [but it
* should also return a ::CommDlgExtendedError() if that is the case].
*
**/
DWORD ThisErr=0;
BYTE DidRetry=0;
if(::IsBadStringPtr(FileNames, FileNamesLength)) throw STD(_T("The FileNames parameter is incorrect"));
ofn.lStructSize = sizeof(OPENFILENAME); /* See MSDN notes about this member in Pre-Win2K systems. */
ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
ofn.Flags = ofn.Flags | OFN_ALLOWMULTISELECT;
OfnRetry:
ofn.hwndOwner = TheirhWnd;
ofn.lpstrFile = FileNames;
ofn.nMaxFile = static_cast<DWORD>(FileNamesLength);/* Bad Commdlg, Bad! */
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
/* Fill out filters for text documents, executables and all files. */
ofn.lpstrFilter = _T("All Files (*.*)\0*.*\0\0");
ofn.nFilterIndex = 2;
/* REMEMBER: When you alter ofn->lpstrFilter, don't forget to update ofn->nFilterIndex. */
ofn.lpstrInitialDir = NULL;
ofn.lpfnHook = NULL;
/* Only allow existent files, allow any number and use the new style open dialogs. */
ThisErr = ::GetOpenFileName(&ofn);
FileNames = ofn.lpstrFile;
/** Handle the filename once received from GetOpenFileName(). TODO: We may want to assert whether
* the files exist. That TODO is not necessary in FilePermsBox (The assertion takes place elsewhere).
**/
if(ThisErr != FALSE)
return TRUE;
else
{/** GetOpenFileName() returned an error. FileNames should always be the same as
* ofn.lpstrFile regardless.
**/
switch(::CommDlgExtendedError())
{/* Handle specific cases where GetOpenFileName() failed. eg. CDERR_DIALOGFAILURE */
case CDERR_INITIALIZATION:
{/* Initialisation Failed. Happens on old Windows Versions. */
::SetLastError(ERROR_SUCCESS);
if(! (DidRetry & 1) )
{/* Give the flags a windows 3.x style dialog box. */
ThisErr |= 1;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
goto OfnRetry;
}
else
{/* That didn't help; simply inform the user that this functionality is unavailable. */
throw STD(_T("Error creating \"open...\" common dialog box"));
}/* Clean Up. */
}
case CDERR_MEMALLOCFAILURE:
case FNERR_SUBCLASSFAILURE:
case CDERR_MEMLOCKFAILURE:
{/* Bad Memory. */
throw STD(_T("Could not browse file system due to memory or window creation problem"));
}
case CDERR_STRUCTSIZE:
{/** The structsize member is not the correct size. This occurs because in Win2K+,
* the ofn structure was changed to something bigger. However, this new structure does not
* work in earlier windows versions. When we call ::GetOpenFileName(), it will return this
* error. If we are trying this Win2K+ application in Win9x-, we'll need to call
* ::GetOpenFileName() with the value sizeof(ofn) Win9x- is expecting.
* OPENFILENAME_SIZE_VERSION_400 will help us here. It returns the sizeof(OPENFILENAME)
* we would get if the app was targeted for Win9x-.
**/
if( ! (ThisErr & (1 << 1)))
{
::SetLastError(ERROR_SUCCESS);
DidRetry |= 1 << 1;
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
goto OfnRetry;
}
}
case CDERR_GENERALCODES:
{/* General Codes. (Happens when user presses cancel). Continue normally in this case. */
return FALSE;
}
case FNERR_INVALIDFILENAME:
case FNERR_BUFFERTOOSMALL:
{/* BIG_STRING characters not enough, or there is an invalid filename. */
throw STD(_T("The filename is too long"));
}
default:
{/* Currently Unhandled Error. */
throw STD(_T("Could not browse due to an unknown error"));
}
}
}
}
intptr_t ParseCmdLine(std::basic_string<TCHAR> &sCmdLine)
{/** This procedure is what handles the command line. The return value is either not 2 (we did something).
* or 2 (the command line was empty). This function may throw a tstring exception on error.
*
* Currently handled switches: /? /reg /unreg /dump "FileName"
**/
if(sCmdLine.find(_T("/?")) < sCmdLine.size())
{/* ?: Display Help/ */
::MessageBox(NULL, _T("FilePermsBox.exe [/{un}reg] [/silent] [/allusers] [/meonly] [/?] \"FileName\" [/dump]\n")
_T("/?: Shows this help.\n\"FileName\": Name of the file to edit security. Must be quoted.\n")
_T("/{un}reg: Enables the shell property sheet extension, or removes it.\n")
_T("\t/silent: registers silently. Only valid with /reg.\n")
_T("\t/allusers: registers for all users (this is the default). Only valid with /reg.\n")
_T("\t/meonly: registers for this user only. Only valid with /reg. Do not mix with /allusers\n")
_T("/dump: Displays the security descriptor for the file. Only valid when a filename has been specified.\n\n")
_T("eg. FilePermsBox.exe \"C:\\Windows\\System\" /dump\n\nDumps the security descriptor for ")
_T("\"C:\\Windows\\System\"."),
_T("Command Line Options."), MB_OK | MB_ICONINFORMATION);
return 0;
}
DWORD Flags = 0;
const DWORD RegFlag = 1 << 0, UnregFlag = 1 << 1;
if(sCmdLine.find(_T("/reg")) < sCmdLine.size())
{/* reg: get ready to register */
Flags |= RegFlag;
}
if(sCmdLine.find(_T("/unreg")) < sCmdLine.size())
{/* unreg: get ready to unregister */
Flags |= UnregFlag;
}
if( (Flags & RegFlag) || (Flags & UnregFlag) )
{/* Were we suppose to [un]register? do it here. */
intptr_t dwErr = 0;
HMODULE hFilePermsBoxDll = ::LoadLibrary(_T("FilePermsBox.DLL"));
/* We're required by Microsoft to dynamically link at runtime to DllRegisterServer */
HRESULT (STDAPICALLTYPE *pfnDllInstall)(BOOL, LPCWSTR);
if(!hFilePermsBoxDll) throw STD(_T("A required DLL, FilePermsBox.DLL was not found"));
/* We need DCOM too (according to Microsoft). */
/* Now that the library is loaded, GetProcAddress DllInstall. */
pfnDllInstall = reinterpret_cast<HRESULT (STDAPICALLTYPE *)(BOOL, LPCWSTR)>
(::GetProcAddress(hFilePermsBoxDll, "DllInstall"));
if(!pfnDllInstall)
{/* If we didn't get it, throw an exception */
::FreeLibrary(hFilePermsBoxDll); hFilePermsBoxDll = NULL;
throw STD(_T("The procedure entry point \"DllRegisterServer\" could not be found in FilePermsBox.DLL.")
_T(" Perhaps there is a version mismatch"));
}
else
{/* OK, we got it, call it. */
BOOL bInstall = (Flags & UnregFlag) ? FALSE : TRUE;
dwErr = pfnDllInstall(bInstall, sCmdLine.c_str());
}
/* Cleanup now. */
::FreeLibrary(hFilePermsBoxDll); hFilePermsBoxDll = NULL;
if(dwErr == 2)/* This conflicts with another code, so offset it. */
dwErr = HRESULT_FROM_WIN32(2);
return dwErr;
}
else if( sCmdLine.find(_T('\"')) < sCmdLine.size() &&
sCmdLine.find(_T('\"'), sCmdLine.find(_T('\"')) + 1) < sCmdLine.size() )
{/* There's a possible filename in the command line (at least two quotes). */
size_t start = 1 + sCmdLine.find(_T('\"')) ,
end = sCmdLine.find(_T('\"'), start );
/* Anchor start and end to the two quotes. */
if (::GetFileAttributes(sCmdLine.substr(start, end - start).c_str()) != INVALID_FILE_ATTRIBUTES)
{/* It seems to be a legal filename. */
if(sCmdLine.find(_T("/dump")) < sCmdLine.size())
{/* They want to dump it. Dump it. */
std::basic_string<TCHAR> SDDLString;
if(::GetSDForObject(sCmdLine.substr(start, end - start),
SDDLString, TRUE))
{/* Once the security is obtained, show it to the user. */
std::basic_stringstream<TCHAR> TError;
TError << _T("Security descriptor for object \"") << sCmdLine.substr(start, end - start) << _T("\"\n")
<< SDDLString.c_str();
::MessageBox(NULL, TError.str().c_str(), _T("FilePermsBox - Security descriptor"), MB_OK);
return 0;
}
}
/* Use the net wrapper interface to get to DoSecurityBox */
#if (_MSC_VER >= 1400)
return UseManagedCOMWrapperLib(sCmdLine.substr(start, end - start));
#else /* _MSC_VER */
/* They don't want to dump its SD. Go straight to DoSecurityBox() (no frontend UI). */
std::list<const std::basic_string<TCHAR> > FileNamesCollection;
FileNamesCollection.push_back(sCmdLine.substr(start, end - start));
return DoSecurityBox(NULL, SE_FILE_OBJECT, FileNamesCollection, g_AddWritability);
#endif /* Use the managed C++ / CLI interface for VS2005, and the unmanaged interface otherwise */
}
}
return 2;
}
BOOL WalkDirectory(const std::basic_string<TCHAR> &lpszString,
std::list< const std::basic_string<TCHAR> > &FileNamesCollection, BOOL DirsOrFiles)
{/** This procedure walks the object lpszString and returns the resulting directory tree in FileNamesCollection.
* If DirsOrFiles is TRUE, we walk directories only; if false, we walk files only
**/
HANDLE hDirCmd = NULL;
WIN32_FIND_DATA DirCmdStruct = {0};
DWORD ListErr = ERROR_SUCCESS, dwErr = FALSE;
::SetLastError(ERROR_SUCCESS);
/* We use the last Win32 error code in this function. */
hDirCmd = ::FindFirstFile(lpszString.c_str(), &DirCmdStruct);
if(hDirCmd == INVALID_HANDLE_VALUE || hDirCmd == NULL)
{/* Can't find it eh? just use lpszString as the filename. */
FileNamesCollection.push_back(lpszString.c_str());
return TRUE;
}
do {/* Foreach file object in this FindFirst/FindNext/FindClose handle: */
if(DirCmdStruct.cFileName[0] != _T('.'))
{/* skip . or .. directories */
const std::basic_string<TCHAR> FullFileName =
lpszString.substr(0, 1 + lpszString.find_last_of(_T("\\"))) +
static_cast< const std::basic_string<TCHAR> >(DirCmdStruct.cFileName);
DWORD FileAttrib = ::GetFileAttributes(FullFileName.c_str());
/* Construct a full file pathname, and get its current attributes */
if(FileAttrib != INVALID_FILE_ATTRIBUTES)
{/* This filename is valid. */
if(FileAttrib & FILE_ATTRIBUTE_DIRECTORY)
{/* It's a directory. Do we want it? */
if(DirsOrFiles == TRUE)
{/* Walkit. */
WalkDirectory(FullFileName, FileNamesCollection, TRUE);
}
}
FileNamesCollection.push_back(FullFileName);
}
}
::SetLastError(ERROR_SUCCESS); ListErr = ERROR_SUCCESS;
/* Use FindNextFile to get the next file, and loop. */
dwErr = ::FindNextFile(hDirCmd, &DirCmdStruct);
/* This will set last error to ERROR_NO_MORE_FILES on Failure. */
if(dwErr != TRUE)
ListErr = ::GetLastError();
} while (ListErr == ERROR_SUCCESS);
/* finally, cleanup. */
if(hDirCmd != INVALID_HANDLE_VALUE && hDirCmd != NULL)
::FindClose(hDirCmd); hDirCmd = NULL;
return TRUE;
}