Example #1
0
bool ConsoleHandler::StartShellProcess
(
	const wstring& strCustomShell, 
	const wstring& strInitialDir, 
	const wstring& strUser,
	const wstring& strPassword,
	const wstring& strInitialCmd, 
	const wstring& strConsoleTitle, 
	DWORD dwStartupRows, 
	DWORD dwStartupColumns, 
	bool bDebugFlag
)
{
	wstring strUsername(strUser);
	wstring strDomain;

//	shared_ptr<void> userProfileKey;
//	shared_ptr<void> userEnvironment;
//	shared_ptr<void> userToken;

	if (strUsername.length() > 0)
	{
		size_t pos = strUsername.find(L'\\');
		if (pos != wstring::npos)
		{
			strDomain	= strUsername.substr(0, pos);
			strUsername	= strUsername.substr(pos+1);
		}
/*
		// logon user
		HANDLE hUserToken = NULL;
		::LogonUser(
			strUsername.c_str(), 
			strDomain.length() > 0 ? strDomain.c_str() : NULL, 
			strPassword.c_str(), 
			LOGON32_LOGON_INTERACTIVE, 
			LOGON32_PROVIDER_DEFAULT, 
			&hUserToken);

		userToken.reset(hUserToken, ::CloseHandle);
*/

/*
		::ImpersonateLoggedOnUser(userToken.get());

		wchar_t	szComspec[MAX_PATH];
		::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH);
*/


/*
		// load user's profile
		// seems to be necessary on WinXP for environment strings' expainsion to work properly
		PROFILEINFO userProfile;
		::ZeroMemory(&userProfile, sizeof(PROFILEINFO));
		userProfile.dwSize = sizeof(PROFILEINFO);
		userProfile.lpUserName = const_cast<wchar_t*>(strUser.c_str());
		
		::LoadUserProfile(userToken.get(), &userProfile);
		userProfileKey.reset(userProfile.hProfile, bind<BOOL>(::UnloadUserProfile, userToken.get(), _1));
*/
/*		// load user's environment
		void*	pEnvironment	= NULL;
		::CreateEnvironmentBlock(&pEnvironment, userToken.get(), FALSE);
		userEnvironment.reset(pEnvironment, ::DestroyEnvironmentBlock);
		::RevertToSelf();
*/
	}

	wstring	strShellCmdLine(strCustomShell);
	
	if (strShellCmdLine.length() == 0)
	{
		wchar_t	szComspec[MAX_PATH];

		::ZeroMemory(szComspec, MAX_PATH*sizeof(wchar_t));

		if (strUsername.length() > 0)
		{
/*			// resolve comspec when running as another user
			wchar_t* pszComspec = reinterpret_cast<wchar_t*>(userEnvironment.get());

			while ((pszComspec[0] != L'\x00') && (_wcsnicmp(pszComspec, L"comspec", 7) != 0)) pszComspec += wcslen(pszComspec)+1;

			if (pszComspec[0] != L'\x00')
			{
				strShellCmdLine = (pszComspec + 8);
			}
*/
			if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe";
		}
		else
		{
			if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0)
			{
				strShellCmdLine = szComspec;		
			}

			if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe";
		}
	}

	if (strInitialCmd.length() > 0)
	{
		strShellCmdLine += L" ";
		strShellCmdLine += strInitialCmd;
	}

	wstring	strStartupTitle(strConsoleTitle);

	if (strStartupTitle.length() == 0)
	{
		strStartupTitle = L"Console2 command window";
//		strStartupTitle = str(wformat(L"Console2 command window 0x%08X") % this);
	}

//	wstring strStartupDir((strUsername.length() > 0) ? Helpers::ExpandEnvironmentStringsForUser(userToken, strInitialDir) : Helpers::ExpandEnvironmentStrings(strInitialDir));
	wstring strStartupDir((strUsername.length() > 0) ? strInitialDir : Helpers::ExpandEnvironmentStrings(strInitialDir));

	if (strStartupDir.length() > 0)
	{
		if ((*(strStartupDir.end() - 1) == L'\"') && (*strStartupDir.begin() != L'\"'))
		{
			// startup dir name ends with ", but doesn't start with ", the user passed
			// something like "C:\" as the parameter, it got parsed to C:", remove the trailing "
			//
			// This is a common mistake, thus the check...
			strStartupDir = strStartupDir.substr(0, strStartupDir.length()-1);
		}

		// startup dir doesn't end with \, add it
		if (*(strStartupDir.end() - 1) != L'\\') strStartupDir += L'\\';

		// check if startup directory exists
		DWORD dwDirAttributes = ::GetFileAttributes(strStartupDir.c_str());

		if ((dwDirAttributes == INVALID_FILE_ATTRIBUTES) ||
			(dwDirAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
		{
			// no directory, use Console.exe directory
			strStartupDir = Helpers::GetModulePath(NULL);
		}
	}

	// setup the startup info struct
	STARTUPINFO si;
	::ZeroMemory(&si, sizeof(STARTUPINFO));

	si.cb			= sizeof(STARTUPINFO);
	si.lpTitle		= const_cast<wchar_t*>(strStartupTitle.c_str());

	if (g_settingsHandler->GetConsoleSettings().bStartHidden)
	{
		// Starting Windows console window hidden causes problems with 
		// some GUI apps started from Console that use SW_SHOWDEFAULT to 
		// initially show their main window (i.e. the window inherits our 
		// SW_HIDE flag and remains invisible :-)
		si.dwFlags		= STARTF_USESHOWWINDOW;
		si.wShowWindow	= SW_HIDE;
	}
	else
	{
		// To avoid invisible GUI windows, default settings will create
		// a Windows console window far offscreen and hide the window
		// after it has been created.
		//
		// This approach can flash console window's taskbar button and
		// taskbar button can sometimes remain visible, but nothing is perfect :)
		si.dwFlags		= STARTF_USEPOSITION;
		si.dwX			= 0x7FFF;
		si.dwY			= 0x7FFF;
	}
	
	PROCESS_INFORMATION pi;
	// we must use CREATE_UNICODE_ENVIRONMENT here, since s_environmentBlock contains Unicode strings
	DWORD dwStartupFlags = CREATE_NEW_CONSOLE|CREATE_SUSPENDED|CREATE_UNICODE_ENVIRONMENT;

	// TODO: not supported yet
	//if (bDebugFlag) dwStartupFlags |= DEBUG_PROCESS;

	
	if (strUsername.length() > 0)
	{
		if (!::CreateProcessWithLogonW(
			strUsername.c_str(), 
			strDomain.length() > 0 ? strDomain.c_str() : NULL, 
			strPassword.c_str(), 
			LOGON_WITH_PROFILE,
			NULL,
//			const_cast<wchar_t*>(Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine).c_str()),
			const_cast<wchar_t*>(strShellCmdLine.c_str()),
			dwStartupFlags,
//			userEnvironment.get(),
			NULL,
			(strStartupDir.length() > 0) ? const_cast<wchar_t*>(strStartupDir.c_str()) : NULL,
			&si,
			&pi))
		{
			throw ConsoleException(str(wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % strShellCmdLine % strUser));
		}
	}
	else
	{
		if (!::CreateProcess(
				NULL,
				const_cast<wchar_t*>(Helpers::ExpandEnvironmentStrings(strShellCmdLine).c_str()),
				NULL,
				NULL,
				FALSE,
				dwStartupFlags,
				s_environmentBlock.get(),
				(strStartupDir.length() > 0) ? const_cast<wchar_t*>(strStartupDir.c_str()) : NULL,
				&si,
				&pi))
		{
			throw ConsoleException(str(wformat(Helpers::LoadString(IDS_ERR_CANT_START_SHELL)) % strShellCmdLine));
		}
	}

	// create shared memory objects
	CreateSharedObjects(pi.dwProcessId, strUser);
	CreateWatchdog();

	// write startup params
	m_consoleParams->dwConsoleMainThreadId	= pi.dwThreadId;
	m_consoleParams->dwParentProcessId		= ::GetCurrentProcessId();
	m_consoleParams->dwNotificationTimeout	= g_settingsHandler->GetConsoleSettings().dwChangeRefreshInterval;
	m_consoleParams->dwRefreshInterval		= g_settingsHandler->GetConsoleSettings().dwRefreshInterval;
	m_consoleParams->dwRows					= dwStartupRows;
	m_consoleParams->dwColumns				= dwStartupColumns;
	m_consoleParams->dwBufferRows			= g_settingsHandler->GetConsoleSettings().dwBufferRows;
	m_consoleParams->dwBufferColumns		= g_settingsHandler->GetConsoleSettings().dwBufferColumns;

	m_hConsoleProcess = shared_ptr<void>(pi.hProcess, ::CloseHandle);

	// inject our hook DLL into console process
	if (!InjectHookDLL(pi)) return false;

	// resume the console process
	::ResumeThread(pi.hThread);
	::CloseHandle(pi.hThread);

	// wait for hook DLL to set console handle
	if (::WaitForSingleObject(m_consoleParams.GetReqEvent(), 10000) == WAIT_TIMEOUT) return false;

	::ShowWindow(m_consoleParams->hwndConsoleWindow, SW_HIDE);

	return true;
}
Example #2
0
bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstring& strInitialDir, const wstring& strInitialCmd, const wstring& strConsoleTitle, DWORD dwStartupRows, DWORD dwStartupColumns, bool bDebugFlag)
{
	wstring	strShellCmdLine(strCustomShell);
	
	if (strShellCmdLine.length() == 0)
	{
		wchar_t	szComspec[MAX_PATH];

		::ZeroMemory(szComspec, MAX_PATH*sizeof(wchar_t));

		if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0)
		{
			strShellCmdLine = szComspec;		
		}
		else
		{
			strShellCmdLine = L"cmd.exe";
		}
	}

	if (strInitialCmd.length() > 0)
	{
		strShellCmdLine += L" ";
		strShellCmdLine += strInitialCmd;
	}

	wstring	strStartupTitle(strConsoleTitle);

	if (strStartupTitle.length() == 0)
	{
		strStartupTitle = L"Console2 command window";
//		strStartupTitle = str(wformat(L"Console2 command window 0x%08X") % this);
	}

	wstring strStartupDir(strInitialDir);

	if (strStartupDir.length())
	{
		// check if startup directory exists
		DWORD dwDirAttributes = ::GetFileAttributes(strStartupDir.c_str());

		if ((dwDirAttributes == INVALID_FILE_ATTRIBUTES) ||
			(dwDirAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
		{
			// no directory, use Console.exe directory
			strStartupDir = Helpers::GetModulePath(NULL);
		}
	}

	// setup the startup info struct
	STARTUPINFO si;
	::ZeroMemory(&si, sizeof(STARTUPINFO));
	si.dwFlags		= STARTF_USESHOWWINDOW;
	si.cb			= sizeof(STARTUPINFO);
	si.wShowWindow	= SW_HIDE;
	si.lpTitle		= const_cast<wchar_t*>(strStartupTitle.c_str());

	PROCESS_INFORMATION pi;
	DWORD				dwStartupFlags = CREATE_NEW_CONSOLE|CREATE_SUSPENDED;

	// TODO: not supported yet
	//if (bDebugFlag) dwStartupFlags |= DEBUG_PROCESS;

	if (!::CreateProcess(
			NULL,
			const_cast<wchar_t*>(Helpers::ExpandEnvironmentStrings(strShellCmdLine).c_str()),
			NULL,
			NULL,
			FALSE,
			dwStartupFlags,
			NULL,
			(strStartupDir.length() > 0) ? const_cast<wchar_t*>(Helpers::ExpandEnvironmentStrings(strStartupDir).c_str()) : NULL,
			&si,
			&pi))
	{
		return false;
	}

	// create shared memory objects
	CreateSharedObjects(pi.dwProcessId);

	// write startup params
	m_consoleParams->dwConsoleMainThreadId	= pi.dwThreadId;
	m_consoleParams->dwParentProcessId		= ::GetCurrentProcessId();
	m_consoleParams->dwNotificationTimeout	= g_settingsHandler->GetConsoleSettings().dwChangeRefreshInterval;
	m_consoleParams->dwRefreshInterval		= g_settingsHandler->GetConsoleSettings().dwRefreshInterval;
	m_consoleParams->dwRows					= dwStartupRows;
	m_consoleParams->dwColumns				= dwStartupColumns;
	m_consoleParams->dwBufferRows			= g_settingsHandler->GetConsoleSettings().dwBufferRows;
	m_consoleParams->dwBufferColumns		= g_settingsHandler->GetConsoleSettings().dwBufferColumns;

	m_hConsoleProcess = shared_ptr<void>(pi.hProcess, ::CloseHandle);

	// inject our hook DLL into console process
	if (!InjectHookDLL()) return false;

	// resume the console process
	::ResumeThread(pi.hThread);
	::CloseHandle(pi.hThread);

	// wait for hook DLL to set console handle
	if (::WaitForSingleObject(m_consoleParams.GetReqEvent(), 10000) == WAIT_TIMEOUT) return false;

	return true;
}
Example #3
0
void ConsoleHandler::CreateShellProcess
(
	const wstring& strShell,
	const wstring& strInitialDir,
	const UserCredentials& userCredentials,
	const wstring& strInitialCmd,
	const wstring& strConsoleTitle,
	PROCESS_INFORMATION& pi
)
{
	std::unique_ptr<void, DestroyEnvironmentBlockHelper> userEnvironment;
	std::unique_ptr<void, CloseHandleHelper>             userToken;

	if (userCredentials.strUsername.length() > 0)
	{
		if (!userCredentials.netOnly)
		{
			// logon user
			HANDLE hUserToken = NULL;
			if( !::LogonUser(
				userCredentials.strUsername.c_str(),
				userCredentials.strDomain.length() > 0 ? userCredentials.strDomain.c_str() : NULL,
				userCredentials.password.c_str(),
				LOGON32_LOGON_INTERACTIVE,
				LOGON32_PROVIDER_DEFAULT,
				&hUserToken) || !::ImpersonateLoggedOnUser(hUserToken) )
			{
				Win32Exception err(::GetLastError());
				throw ConsoleException(boost::str(boost::wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % L"?" % userCredentials.user % err.what()));
			}
			userToken.reset(hUserToken);

			/*
			// load user's profile
			// seems to be necessary on WinXP for environment strings' expainsion to work properly
			PROFILEINFO userProfile;
			::ZeroMemory(&userProfile, sizeof(PROFILEINFO));
			userProfile.dwSize = sizeof(PROFILEINFO);
			userProfile.lpUserName = const_cast<wchar_t*>(userCredentials.strUsername.c_str());

			::LoadUserProfile(userToken.get(), &userProfile);
			userProfileKey.reset(userProfile.hProfile, bind<BOOL>(::UnloadUserProfile, userToken.get(), _1));
			*/

			// load user's environment
			void*	pEnvironment = nullptr;
			if( !::CreateEnvironmentBlock(&pEnvironment, userToken.get(), FALSE) )
			{
				Win32Exception err(::GetLastError());
				::RevertToSelf();
				throw ConsoleException(boost::str(boost::wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % L"?" % userCredentials.user % err.what()));
			}
			userEnvironment.reset(pEnvironment);
		}
	}

	wstring	strShellCmdLine(strShell);

	if (strShellCmdLine.length() == 0)
	{
		wchar_t	szComspec[MAX_PATH];

		::ZeroMemory(szComspec, MAX_PATH*sizeof(wchar_t));

		if (userEnvironment.get())
		{
			// resolve comspec when running as another user
			wchar_t* pszComspec = reinterpret_cast<wchar_t*>(userEnvironment.get());

			while ((pszComspec[0] != L'\x00') && (_wcsnicmp(pszComspec, L"comspec", 7) != 0)) pszComspec += wcslen(pszComspec)+1;

			if (pszComspec[0] != L'\x00')
			{
				strShellCmdLine = (pszComspec + 8);
			}

			if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe";
		}
		else
		{
			if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0)
			{
				strShellCmdLine = szComspec;
			}

			if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe";
		}
	}

	if (strInitialCmd.length() > 0)
	{
		strShellCmdLine += L" ";
		strShellCmdLine += strInitialCmd;
	}

	wstring	strStartupTitle(strConsoleTitle);

	if (strStartupTitle.length() == 0)
	{
		strStartupTitle = L"Console2 command window";
		//		strStartupTitle = boost::str(boost::wformat(L"Console2 command window 0x%08X") % this);
	}

	wstring strStartupDir(
		userToken.get() ?
		Helpers::ExpandEnvironmentStringsForUser(userToken.get(), strInitialDir) :
		Helpers::ExpandEnvironmentStrings(strInitialDir));

	if (strStartupDir.length() > 0)
	{
		if ((*(strStartupDir.end() - 1) == L'\"') && (*strStartupDir.begin() != L'\"'))
		{
			// startup dir name ends with ", but doesn't start with ", the user passed
			// something like "C:\" as the parameter, it got parsed to C:", remove the trailing "
			//
			// This is a common mistake, thus the check...
			strStartupDir = strStartupDir.substr(0, strStartupDir.length()-1);
		}

		// startup dir doesn't end with \, add it
		if (*(strStartupDir.end() - 1) != L'\\') strStartupDir += L'\\';

		// check if startup directory exists
		DWORD dwDirAttributes = ::GetFileAttributes(strStartupDir.c_str());

		if ((dwDirAttributes == INVALID_FILE_ATTRIBUTES) ||
			(dwDirAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
		{
			// no directory, use Console.exe directory
			strStartupDir = Helpers::GetModulePath(NULL);
		}
	}

	wstring strCmdLine(
		userToken.get() ?
		Helpers::ExpandEnvironmentStringsForUser(userToken.get(), strShellCmdLine) :
		Helpers::ExpandEnvironmentStrings(strShellCmdLine));

	if( userToken.get() )
		::RevertToSelf();

	// setup the startup info struct
	STARTUPINFO si;
	::ZeroMemory(&si, sizeof(STARTUPINFO));

	si.cb			= sizeof(STARTUPINFO);
	si.lpTitle		= const_cast<wchar_t*>(strStartupTitle.c_str());

	if (g_settingsHandler->GetConsoleSettings().bStartHidden)
	{
		// Starting Windows console window hidden causes problems with 
		// some GUI apps started from Console that use SW_SHOWDEFAULT to 
		// initially show their main window (i.e. the window inherits our 
		// SW_HIDE flag and remains invisible :-)
		si.dwFlags		= STARTF_USESHOWWINDOW;
		si.wShowWindow	= SW_HIDE;
	}
	else
	{
		// To avoid invisible GUI windows, default settings will create
		// a Windows console window far offscreen and hide the window
		// after it has been created.
		//
		// This approach can flash console window's taskbar button and
		// taskbar button can sometimes remain visible, but nothing is perfect :)
		si.dwFlags		= STARTF_USEPOSITION;
		si.dwX			= 0x7FFF;
		si.dwY			= 0x7FFF;
	}

	// we must use CREATE_UNICODE_ENVIRONMENT here, since s_environmentBlock contains Unicode strings
	DWORD dwStartupFlags = CREATE_NEW_CONSOLE|CREATE_SUSPENDED|CREATE_UNICODE_ENVIRONMENT;

	// TODO: not supported yet
	//if (bDebugFlag) dwStartupFlags |= DEBUG_PROCESS;

	if (userCredentials.strUsername.length() > 0)
	{
		if( !::CreateProcessWithLogonW(
			userCredentials.strUsername.c_str(),
			userCredentials.strDomain.length() > 0 ? userCredentials.strDomain.c_str() : NULL,
			userCredentials.password.c_str(), 
			userCredentials.netOnly? LOGON_NETCREDENTIALS_ONLY : LOGON_WITH_PROFILE,
			NULL,
			const_cast<wchar_t*>(strCmdLine.c_str()),
			dwStartupFlags,
			s_environmentBlock.get(),
			(strStartupDir.length() > 0) ? const_cast<wchar_t*>(strStartupDir.c_str()) : NULL,
			&si,
			&pi))
		{
			Win32Exception err(::GetLastError());
			throw ConsoleException(boost::str(boost::wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % strShellCmdLine % userCredentials.user % err.what()));
		}
	}
	else
	{
		if (!::CreateProcess(
			NULL,
			const_cast<wchar_t*>(strCmdLine.c_str()),
			NULL,
			NULL,
			FALSE,
			dwStartupFlags,
			s_environmentBlock.get(),
			(strStartupDir.length() > 0) ? const_cast<wchar_t*>(strStartupDir.c_str()) : NULL,
			&si,
			&pi))
		{
			Win32Exception err(::GetLastError());
			throw ConsoleException(boost::str(boost::wformat(Helpers::LoadString(IDS_ERR_CANT_START_SHELL)) % strShellCmdLine % err.what()));
		}
	}
}