Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1279 lines
39 KiB

//+----------------------------------------------------------------------------
//
// File: ActList.cpp
//
// Module: CMDIAL32.DLL
//
// Synopsis: Implement the two connect action list class
// CAction and CActionList
//
// Copyright (c) 1997-1999 Microsoft Corporation
//
// Author: fengsun Created 11/14/97
//
//+----------------------------------------------------------------------------
#include "cmmaster.h"
#include "ActList.h"
#include "stp_str.h"
//
// Include the custom action parsing routine that CM and CMAK now share, HrParseCustomActionString
//
#include "parseca.cpp"
//
// Constructor and destructor
//
CActionList::CActionList()
{
m_pActionList = NULL;
m_nNum = 0;
m_nSize = 0;
m_pszType = NULL;
}
CActionList::~CActionList()
{
for (UINT i = 0; i < m_nNum; i++)
{
delete m_pActionList[i];
}
CmFree(m_pActionList);
}
//+----------------------------------------------------------------------------
//
// Function: CActionList::Add
//
// Synopsis: Dynamic array function. Append the element at the end of the array
// Grow the array if nessesary
//
// Arguments: CAction* pAction - element to be added
//
// Returns: Nothing
//
// History: Fengsun Created Header 11/14/97
// tomkel Fixed PREFIX issues 11/21/2000
//
//+----------------------------------------------------------------------------
void CActionList::Add(CAction* pAction)
{
MYDBGASSERT(m_nNum <= m_nSize);
MYDBGASSERT(m_nSize == 0 || m_pActionList!=NULL); // if (m_nSize!=0) ASSERT(m_pActionList!=NULL);
m_nNum++;
if (m_nNum > m_nSize)
{
//
// Either there is not enough room OR m_pActionList is NULL (this
// is the first call to Add). Need to allocate memory
//
CAction** pNewList = (CAction**)CmMalloc((m_nSize + GROW_BY)*sizeof(CAction*));
MYDBGASSERT(pNewList);
if (m_pActionList && pNewList)
{
//
// Memory was allocated and there is something to copy from m_pActionList
//
CopyMemory(pNewList, m_pActionList, (m_nSize)*sizeof(CAction*));
}
if (pNewList)
{
//
// Memory was allocated
//
CmFree(m_pActionList);
m_pActionList = pNewList;
m_nSize += GROW_BY;
//
// Add the action
//
m_pActionList[m_nNum - 1] = pAction;
}
else
{
//
// Memory was not allocated, so Add did not happen
// Need to decrement the number of items in list (m_nNum)
// since it was inceremented at the beginning.
//
m_nNum--;
}
}
else
{
//
// Just add the action to the end
//
m_pActionList[m_nNum - 1] = pAction;
}
}
//+----------------------------------------------------------------------------
//
// Function: CActionList::GetAt
//
// Synopsis: Dynamic array fuction. Get the element at nIndex
//
// Arguments: UINT nIndex -
//
// Returns: inline CAction* -
//
// History: fengsun Created Header 11/14/97
//
//+----------------------------------------------------------------------------
inline CAction* CActionList::GetAt(UINT nIndex)
{
MYDBGASSERT(nIndex<m_nNum);
MYDBGASSERT(m_pActionList);
MYDBGASSERT(m_nNum <= m_nSize);
return m_pActionList[nIndex];
}
//+----------------------------------------------------------------------------
//
// Function: CActionList::Append
//
// Synopsis: Append new actions to the list from profile
//
// Arguments: const CIni* piniService - The service file containing actions information
// LPCTSTR pszSection - The section name
//
// Returns: TRUE if an action was appended to the list
//
// History: fengsun Created Header 11/14/97
// nickball Removed current directory assumptions, and added piniProfile
// nickball Added Return code 03/22/99
//
//+----------------------------------------------------------------------------
BOOL CActionList::Append(const CIni* piniService, LPCTSTR pszSection)
{
MYDBGASSERT(piniService);
BOOL bRet = FALSE;
//
// Read each of the entries and add to our list
// Start from 0 till the first empty entry
//
for (DWORD dwIdx=0; ; dwIdx++)
{
TCHAR szEntry[32]; // hold the entry name
wsprintfU(szEntry, TEXT("%u"), dwIdx);
LPTSTR pszCmd = piniService->GPPS(pszSection, szEntry); // Command line
if (*pszCmd == TEXT('\0'))
{
//
// No more entries
//
CmFree(pszCmd);
break;
}
//
// Read the flag
//
UINT iFlag = 0;
if (pszSection && pszSection[0])
{
wsprintfU(szEntry, c_pszCmEntryConactFlags, dwIdx); //0&Flags
iFlag = (UINT)piniService->GPPI(pszSection, szEntry, 0);
}
//
// Read the description
//
LPTSTR pszDescript = NULL;
wsprintfU(szEntry, c_pszCmEntryConactDesc, dwIdx); //0&Description
pszDescript = piniService->GPPS(pszSection, szEntry);
//
// CAction is responsible for releasing pszDescript
//
CAction* pAction = new CAction(pszCmd, iFlag, pszDescript);
CmFree(pszCmd);
if (pAction)
{
pAction->ConvertRelativePath(piniService);
ASSERT_VALID(pAction);
pAction->ExpandEnvironmentStringsInCommand();
Add(pAction);
bRet = TRUE;
}
}
if (bRet)
{
m_pszType = pszSection;
}
return bRet;
}
//+----------------------------------------------------------------------------
//
// Function: CActionList::RunAccordType
//
// Synopsis: Run the action list according to the connection type
//
// Arguments: HWND hwndDlg - The parent window
// _ArgsStruct *pArgs -
// BOOL fStatusMsgOnFailure - Whether to display a status message
// to the user in the event of failure
// BOOL fOnError - are we running OnError connect action?
//
// Returns: BOOL - FALSE, if some sync action failed to start or returns failed
//
// History: Fengsun Created Header 12/5/97
//
//+----------------------------------------------------------------------------
BOOL CActionList::RunAccordType(HWND hwndDlg, _ArgsStruct *pArgs, BOOL fStatusMsgOnFailure, BOOL fOnError)
{
//
// Set the flag, so CM will not handle WM_TIMER and RAS messages
//
pArgs->fIgnoreTimerRasMsg = TRUE;
BOOL fRetValue = Run(hwndDlg, pArgs, FALSE, fStatusMsgOnFailure, fOnError);//fAddWatch = FALSE
pArgs->fIgnoreTimerRasMsg = FALSE;
return fRetValue;
}
//+----------------------------------------------------------------------------
//
// Function: CActionList::Run
//
// Synopsis: Run the action list
//
// Arguments: HWND hwndDlg - The parent window, which is diabled during the process
// ArgsStruct *pArgs -
// BOOL fAddWatch - If true, will add the process as watch process,
// BOOL fStatusMsgOnFailure - Whether to display a status message
// to the user in the event of failure
// BOOL fOnError - are we running OnError connect action?
//
// Returns: BOOL - FALSE, if some sync action failed to start or returns failed
//
// History: fengsun Created Header 11/14/97
//
//+----------------------------------------------------------------------------
BOOL CActionList::Run(HWND hwndDlg, ArgsStruct *pArgs, BOOL fAddWatch, BOOL fStatusMsgOnFailure, BOOL fOnError)
{
//
// Disable the window, and enable it on return
//
CFreezeWindow FreezeWindow(hwndDlg);
for (UINT i = 0; i < GetSize(); i++)
{
CAction* pAction = (CAction*)GetAt(i);
DWORD dwLoadType = (DWORD)-1;
ASSERT_VALID(pAction);
MYDBGASSERT(m_pszType);
//
// Lets check the flags value to see if this connect action should
// run for this type of connection.
//
if (FALSE == pAction->RunConnectActionForCurrentConnection(pArgs))
{
continue;
}
//
// Replace %xxxx% with the value
//
pAction->ExpandMacros(pArgs);
//
// Also expand any environment variables
// NOTE: the order (macros vs. env vars) is deliberate. Macros get
// expanded first.
//
pAction->ExpandEnvironmentStringsInParams();
//
// Check to see if we can run the action @ this moment
//
if (FALSE == pAction->IsAllowed(pArgs, &dwLoadType))
{
//
// If not allowed, log the fact that we didn't run this connect action
// and then just skip it.
//
pArgs->Log.Log(CUSTOMACTION_NOT_ALLOWED, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
continue;
}
//
// If this customaction might bring up UI
//
if (pAction->HasUI())
{
//
// If we are in unattended mode, don't run any connect actions
//
if (pArgs->dwFlags & FL_UNATTENDED)
{
pArgs->Log.Log(CUSTOMACTION_NOT_ALLOWED, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
CMTRACE(TEXT("Run: skipped past a customaction because we are in unattended mode"));
continue;
}
//
// Custom actions processed during a Fast User Switch can put up UI requiring
// user input, effectively blocking CM.
//
if (pArgs->fInFastUserSwitch)
{
CMASSERTMSG((CM_CREDS_GLOBAL != pArgs->dwCurrentCredentialType),
TEXT("CActionList::Run - in FUS disconnect, but connectoid has global creds!"));
pArgs->Log.Log(CUSTOMACTION_NOT_ALLOWED, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
CMTRACE(TEXT("Run: skipped past a singleuser DLL connectaction because of FUS"));
continue;
}
}
if (pAction->IsDll())
{
DWORD dwActionRetValue=0; // the connect action return value, in COM format
BOOL bLoadSucceed = FALSE;
if (hwndDlg)
{
//
// Display description for DLL
//
if (pAction->GetDescription())
{
LPTSTR lpszText = CmFmtMsg(g_hInst, IDMSG_CONN_ACTION_RUNNING, pAction->GetDescription());
//
// Update the main dialog status window
//
SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, lpszText);
CmFree(lpszText);
}
}
bLoadSucceed = pAction->RunAsDll(hwndDlg, dwActionRetValue, dwLoadType);
if (bLoadSucceed)
{
pArgs->Log.Log(CUSTOMACTIONDLL, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()),
pAction->GetProgram(), dwActionRetValue);
}
else
{
pArgs->Log.Log(CUSTOMACTION_WONT_RUN, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()),
pAction->GetProgram());
}
//
// Failed to start the action, or the action returned failure
//
if (FAILED(dwActionRetValue) || !bLoadSucceed)
{
LPTSTR lpszText = NULL;
if (fStatusMsgOnFailure &&
hwndDlg &&
pAction->GetDescription())
{
if (bLoadSucceed)
{
lpszText = CmFmtMsg(g_hInst, IDMSG_CONN_ACTION_FAILED,
pAction->GetDescription(), dwActionRetValue);
}
else
{
lpszText = CmFmtMsg(g_hInst, IDMSG_CONN_ACTION_NOTFOUND,
pAction->GetDescription());
}
//
// Update the main dialog status window
//
SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, lpszText);
}
if (!fOnError)
{
DWORD dwError = 0;
if (bLoadSucceed)
{
dwError = dwActionRetValue;
}
else
{
dwError = ERROR_DLL_NOT_FOUND;
}
pArgs->Log.Log(ONERROR_EVENT, dwError, pAction->GetDescription());
//
// We'll run On-Error connect actions if we are not already running OnError
// connect action. This is to prevent infinite loops.
//
CActionList OnErrorActList;
OnErrorActList.Append(pArgs->piniService, c_pszCmSectionOnError);
//
// fStatusMsgOnFailure = FALSE
//
OnErrorActList.RunAccordType(hwndDlg, pArgs, FALSE, TRUE);
//
// Update the program state
//
if (fStatusMsgOnFailure)
{
lstrcpynU(pArgs->szLastErrorSrc, pAction->GetDescription(), MAX_LASTERR_LEN);
pArgs->dwExitCode = dwError;
SetInteractive(pArgs->hwndMainDlg, pArgs);
pArgs->psState = PS_Error;
}
}
if (lpszText)
{
//
// restore the failure msg of the previous connect action
//
SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, lpszText);
CmFree(lpszText);
}
//
// Note that if a DLL connect action fails, we will stop processing connect actions.
// If the fStatusMsgOnFailure flag is set, then we won't show an error message
// but connect action processing will still halt (we do this in cases where the user
// isn't going to care such as oncancel actions, onerror actions, and cases where
// disconnect action fail).
//
return FALSE;
}
}
else
{
HANDLE hProcess = NULL;
TCHAR szDesktopName[MAX_PATH];
TCHAR szWinDesktop[MAX_PATH];
if (IsLogonAsSystem())
{
DWORD cb;
HDESK hDesk = GetThreadDesktop(GetCurrentThreadId());
//
// Get the name of the desktop. Normally returns default or Winlogon or system or WinNT
// On Win95/98 GetUserObjectInformation is not supported and thus the desktop name
// will be empty so we will use the good old API
//
szDesktopName[0] = 0;
if (hDesk && GetUserObjectInformation(hDesk, UOI_NAME, szDesktopName, sizeof(szDesktopName), &cb))
{
lstrcpyU(szWinDesktop, TEXT("Winsta0\\"));
lstrcatU(szWinDesktop, szDesktopName);
CMTRACE1(TEXT("CActionList::Run - Desktop = %s"), MYDBGSTR(szWinDesktop));
hProcess = pAction->RunAsExeFromSystem(&pArgs->m_ShellDll, szWinDesktop, dwLoadType);
if (NULL != hProcess)
{
pArgs->Log.Log(CUSTOMACTIONEXE, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
}
else
{
pArgs->Log.Log(CUSTOMACTION_WONT_RUN, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
}
}
else
{
//
// Don't run action if we don't have desktop
//
CMTRACE1(TEXT("CActionList::Run/GetUserObjectInformation failed, GLE=%u"), GetLastError());
continue;
}
}
else
{
hProcess = pAction->RunAsExe(&pArgs->m_ShellDll);
if (NULL != hProcess)
{
pArgs->Log.Log(CUSTOMACTIONEXE, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
}
else
{
pArgs->Log.Log(CUSTOMACTION_WONT_RUN, m_pszType, SAFE_LOG_ARG(pAction->GetDescription()), pAction->GetProgram());
}
}
if (hProcess)
{
if (fAddWatch)
{
AddWatchProcess(pArgs,hProcess); // watch for process termination
}
else
{
CloseHandle(hProcess);
}
}
}
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: CAction::ParseCmdLine
//
// Synopsis: This function parses the given command line into the program,
// dll function name (if required), and the parameters (if any).
// The individual command line parts are stored in member vars.
//
// Arguments: LPTSTR pszCmdLine - connect action command line to parse
//
// Returns: Nothing
//
// History: quintinb original code in Profwiz.cpp ReadConList()
// fengsun copied and modified 4/16/98
// quintinb Rewrote and commonized with the Profwiz version 04/21/00
//
//+----------------------------------------------------------------------------
void CAction::ParseCmdLine(LPTSTR pszCmdLine)
{
m_pszFunction = m_pszProgram = m_pszParams = NULL;
CmStrTrim(pszCmdLine);
HRESULT hr = HrParseCustomActionString(pszCmdLine, &m_pszProgram, &m_pszParams, &m_pszFunction);
MYDBGASSERT(SUCCEEDED(hr));
if (NULL == m_pszProgram)
{
MYDBGASSERT(FALSE); // we should never have a NULL program
m_pszProgram = CmStrCpyAlloc(TEXT(""));
}
if (NULL == m_pszParams)
{
m_pszParams = CmStrCpyAlloc(TEXT(""));
}
if (NULL == m_pszFunction)
{
m_pszFunction = CmStrCpyAlloc(TEXT(""));
}
//
// If we have a function, then the program was a Dll
//
m_fIsDll = (m_pszFunction && (TEXT('\0') != m_pszFunction[0]));
}
//+----------------------------------------------------------------------------
//
// Function: CAction::CAction
//
// Synopsis: Constructor
//
// Arguments: LPTSTR lpCommandLine - The command read from the profile
// CAction is responsible to free it
// UINT dwFlags - The flags read from the profile
// LPTSTR lpDescript - The description of the connect action read from
// profile. CAction is responsible to free it.
//
// Returns: Nothing
//
// History: fengsun Created Header 4/15/98
//
//+----------------------------------------------------------------------------
CAction::CAction(LPTSTR lpCommandLine, UINT dwFlags, LPTSTR lpDescript)
{
m_dwFlags = dwFlags;
m_pszDescription = lpDescript;
//
// Get all information from command line, including
// Program name, function name, parameters
//
ParseCmdLine(lpCommandLine);
//
// If this is a DLL, but there is no description, use the name of the file
// Can not use C Run Time routine _tsplitpath()
//
if (m_fIsDll && (m_pszDescription == NULL || m_pszDescription[0]==TEXT('\0')))
{
//
// Find the last '\\' to get only the file name
//
LPTSTR pszTmp = CmStrrchr(m_pszProgram, '\\');
if (pszTmp == NULL)
{
pszTmp = m_pszProgram;
}
else
{
pszTmp++;
}
CmFree(m_pszDescription);
m_pszDescription = CmStrCpyAlloc(pszTmp);
}
}
CAction::~CAction()
{
CmFree(m_pszProgram);
CmFree(m_pszParams);
CmFree(m_pszFunction);
CmFree(m_pszDescription);
}
//+----------------------------------------------------------------------------
//
// Function: CAction::RunAsDll
//
// Synopsis: Run the action as a Dll
// Format is: DllName.dll FunctionName Argument
// Long file name is enclosed by '+'
//
// Arguments: HWND hwndDlg - The parent window
// DWORD& dwReturnValue - The return value of the dll fuction
// DWORD dwLoadType - The permitted load location
//
// Returns: BOOL - TRUE, if the action is a Dll
//
// History: fengsun Created Header 11/14/97
//
//+----------------------------------------------------------------------------
BOOL CAction::RunAsDll(HWND hwndDlg, OUT DWORD& dwReturnValue, DWORD dwLoadType) const
{
MYDBGASSERT(IsDll());
dwReturnValue = FALSE;
LPWSTR pszwModuleName = NULL;
//
// Determine the module name to be used
//
if (!GetLoadDirWithAlloc(dwLoadType, &pszwModuleName))
{
CMASSERTMSG(FALSE, TEXT("CAction::RunAsDll -- GetLoadDirWithAlloc Failed."));
CmFree(pszwModuleName);
return FALSE;
}
//
// Load the module
//
HINSTANCE hLibrary = LoadLibraryExU(pszwModuleName, NULL, 0);
if (NULL == hLibrary)
{
CMTRACE2(TEXT("RunAsDll() LoadLibrary(%s) failed, GLE=%u."),
MYDBGSTR(pszwModuleName), GetLastError());
CmFree(pszwModuleName);
return FALSE;
}
pfnCmConnectActionFunc pfnFunc;
LPSTR pszFunctionName = NULL;
LPSTR pszParams = NULL;
#ifdef UNICODE
pszFunctionName = WzToSzWithAlloc(m_pszFunction);
#else
pszFunctionName = m_pszFunction;
#endif
//
// Get the Procedure Address
//
pfnFunc = (pfnCmConnectActionFunc)GetProcAddress(hLibrary, pszFunctionName);
#ifdef UNICODE
CmFree(pszFunctionName);
#endif
if (pfnFunc)
{
#if !defined (DEBUG)
__try
{
#endif
#ifdef UNICODE
pszParams = WzToSzWithAlloc(m_pszParams);
#else
pszParams = m_pszParams;
#endif
//
// Execute the Function
//
dwReturnValue = pfnFunc(hwndDlg, hLibrary, pszParams, SW_SHOW);
#ifdef UNICODE
CmFree(pszParams);
#endif
CMTRACE1(TEXT("RunAsDll() Executed module: %s"), MYDBGSTR(pszwModuleName));
CMTRACE1(TEXT("\tFunction: %s"), MYDBGSTR(m_pszFunction));
CMTRACE1(TEXT("\tParams: %s"), MYDBGSTR(m_pszParams));
CMTRACE2(TEXT("\t Return Value: %u = 0x%x"), dwReturnValue, dwReturnValue);
#if !defined (DEBUG)
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
#endif
}
else
{
dwReturnValue = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
CMTRACE3(TEXT("RunAsDll() GetProcAddress(*pszwModuleName=%s,*m_pszFunction=%s) failed, GLE=%u."),
MYDBGSTR(pszwModuleName), MYDBGSTR(m_pszFunction), GetLastError());
}
CmFree(pszwModuleName);
FreeLibrary(hLibrary);
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: CAction::RunAsExe
//
// Synopsis: Run the action as an exe or other shell object
//
// Arguments: CShellDll* pShellDll, pointer to the link to shell32.dll
//
// Returns: HANDLE - The action Process handle, for Win32 only
//
// History: fengsun Created Header 11/14/97
//
//+----------------------------------------------------------------------------
HANDLE CAction::RunAsExe(CShellDll* pShellDll) const
{
// Now we have the exe name and args separated, execute it
SHELLEXECUTEINFO seiInfo;
ZeroMemory(&seiInfo,sizeof(seiInfo));
seiInfo.cbSize = sizeof(seiInfo);
seiInfo.fMask |= SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
seiInfo.lpFile = m_pszProgram;
seiInfo.lpParameters = m_pszParams;
seiInfo.nShow = SW_SHOW;
MYDBGASSERT(pShellDll);
if (!pShellDll->ExecuteEx(&seiInfo))
{
CMTRACE3(TEXT("RunAsExe() ShellExecuteEx() of %s %s GLE=%u."),
MYDBGSTR(m_pszProgram), MYDBGSTR(m_pszParams), GetLastError());
return NULL;
}
return seiInfo.hProcess;
}
//+----------------------------------------------------------------------------
//
// Function: CAction::GetLoadDirWithAlloc
//
// Synopsis: Uses the dwLoadType parameter to decide how the path should be
// modified. This is used in the WinLogon context to prevent just
// any executable from being executed. Must be from the profile dir
// or the system dir.
//
// Arguments: DWORD dwLoadType - Load type, currently 0 == system dir, 1 == profile dir (default)
// LPWSTR pszwPath - string buffer to put the modified path in
//
// Returns: BOOL - TRUE if successful
//
// History: quintinb Created 01/11/2000
// sumitc Change to alloc retval 05/08/2000
//
//+----------------------------------------------------------------------------
BOOL CAction::GetLoadDirWithAlloc(IN DWORD dwLoadType, OUT LPWSTR * ppszwPath) const
{
LPWSTR psz = NULL;
UINT cch = 0;
//
// Check that we have an output buffer
//
if (NULL == ppszwPath)
{
return FALSE;
}
//
// Compute how much space we need
//
if (dwLoadType)
{
// 1 = profile dir
cch += lstrlen(m_pszProgram) + 1;
}
else
{
// 0 = system dir
cch = GetSystemDirectoryU(NULL, 0);
cch += lstrlen(TEXT("\\"));
cch += lstrlen(m_pszProgram) + 1; // is the +1 already in the GetSystemDir retval?
}
//
// Allocate it
//
psz = (LPWSTR) CmMalloc(sizeof(TCHAR) * cch);
if (NULL == psz)
{
return FALSE;
}
//
// Process the load type
//
if (dwLoadType)
{
//
// If relative path, this will already be expanded.
//
lstrcpyU(psz, m_pszProgram);
}
else
{
//
// Force the system directory
//
if (0 == GetSystemDirectoryU(psz, cch))
{
CmFree(psz);
return FALSE;
}
lstrcatU(psz, TEXT("\\"));
lstrcatU(psz, m_pszProgram);
}
*ppszwPath = psz;
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: CAction::RunAsExeFromSystem
//
// Synopsis: Run the action as an exe or other shell object on the choosen desktop
//
// Arguments: CShellDll* pShellDll - pointer to the link to shell32.dll
// LPTSTR pszDesktop - name of the desktop to execute the exe on
// DWORD dwLoadType - location from which to load the exe
//
// Returns: HANDLE - The action Process handle, for Win32 only
//
// History: v-vijayb Created 07/19/99
// nickball Removed fSecurity 07/27/99
//
//+----------------------------------------------------------------------------
HANDLE CAction::RunAsExeFromSystem(CShellDll* pShellDll, LPTSTR pszDesktop, DWORD dwLoadType)
{
STARTUPINFO StartupInfo = {0};
PROCESS_INFORMATION ProcessInfo = {0};
LPWSTR pszwFullPath = NULL;
LPWSTR pszwCommandLine = NULL;
MYDBGASSERT(OS_NT);
StartupInfo.cb = sizeof(StartupInfo);
if (pszDesktop)
{
StartupInfo.lpDesktop = pszDesktop;
StartupInfo.wShowWindow = SW_SHOW;
}
//
// Use an explicit path to the modules to be launched, this
// prevents CreateProcess from picking something up on the path.
//
if (!GetLoadDirWithAlloc(dwLoadType, &pszwFullPath))
{
CMASSERTMSG(FALSE, TEXT("CAction::RunAsExeFromSystem -- GetLoadDirWithAlloc Failed."));
goto Cleanup;
}
pszwCommandLine = CmStrCpyAlloc(m_pszProgram);
if (NULL == pszwCommandLine)
{
CMASSERTMSG(FALSE, TEXT("CAction::RunAsExeFromSystem -- CmStrCpyAlloc Failed."));
goto Cleanup;
}
//
// Add parameters
//
if (NULL == CmStrCatAlloc(&pszwCommandLine, TEXT(" ")))
{
goto Cleanup;
}
if (NULL == CmStrCatAlloc(&pszwCommandLine, m_pszParams))
{
goto Cleanup;
}
CMTRACE1(TEXT("RunAsExeFromSystem/CreateProcess() - Launching %s"), pszwCommandLine);
//
// Launch the modules, this could be CreateProcessU but it isn't necessary as this only runs on NT
//
if (NULL == CreateProcess(pszwFullPath, pszwCommandLine,
NULL, NULL, FALSE, 0,
NULL, NULL,
&StartupInfo, &ProcessInfo))
{
CMTRACE2(TEXT("RunAsExeFromSystem() CreateProcess() of %s failed, GLE=%u."), pszwCommandLine, GetLastError());
ProcessInfo.hProcess = NULL;
ProcessInfo.hThread = NULL;
}
Cleanup:
if (ProcessInfo.hThread)
{
CloseHandle(ProcessInfo.hThread);
}
CmFree(pszwFullPath);
CmFree(pszwCommandLine);
return ProcessInfo.hProcess;
}
//+----------------------------------------------------------------------------
//
// Function: CAction::ExpandMacros
//
// Synopsis: Replace the %xxxxx% in command line with the corresponding value
//
// Arguments: ArgsStruct *pArgs -
//
// Returns: Nothing
//
// History: fengsun Created Header 11/14/97
//
//+----------------------------------------------------------------------------
void CAction::ExpandMacros(ArgsStruct *pArgs)
{
MYDBGASSERT(pArgs);
LPTSTR pszCurr = m_pszParams;
BOOL bValidPropertyName;
while (*pszCurr)
{
if (*pszCurr == TEXT('%'))
{
LPTSTR pszNextPercent = CmStrchr(pszCurr + 1, TEXT('%'));
if (pszNextPercent)
{
LPTSTR pszTmp = (LPTSTR) CmMalloc((DWORD)((pszNextPercent-pszCurr))*sizeof(TCHAR));
if (pszTmp)
{
CopyMemory(pszTmp,pszCurr+1,(pszNextPercent-pszCurr-1)*sizeof(TCHAR));
//
// Get the value from name
//
LPTSTR pszMid = pArgs->GetProperty(pszTmp, &bValidPropertyName);
//
// If the property does not exist, use "NULL"
//
if (pszMid == NULL)
{
pszMid = CmStrCpyAlloc(TEXT("NULL"));
}
else if (pszMid[0] == TEXT('\0'))
{
CmFree(pszMid);
pszMid = CmStrCpyAlloc(TEXT("NULL"));
}
else if ( (lstrcmpiU(pszTmp,TEXT("Profile")) == 0) ||
CmStrchr(pszMid, TEXT(' ')) != NULL)
{
//
// If the name is %Profile% or the value has a space in it,
// Put the string in double quote
//
LPTSTR pszValueInQuote = (LPTSTR)CmMalloc((lstrlenU(pszMid)+3)*sizeof(pszMid[0]));
if (pszValueInQuote)
{
lstrcpyU(pszValueInQuote, TEXT("\""));
lstrcatU(pszValueInQuote, pszMid);
lstrcatU(pszValueInQuote, TEXT("\""));
CmFree(pszMid);
pszMid = pszValueInQuote;
}
else
{
CMTRACE1(TEXT("ExpandMacros() malloc failed, can't put string in double quotes, GLE=%u."), GetLastError());
}
}
//
// if bValidPropertyName is FALSE then leave untouched.
//
if (FALSE == bValidPropertyName)
{
pszCurr = pszNextPercent + 1;
}
else
{
//
// Replace %xxxx% with the value
//
DWORD dwLenPre = (DWORD)(pszCurr - m_pszParams);
DWORD dwLenMid = lstrlenU(pszMid);
DWORD dwLenPost = lstrlenU(pszNextPercent+1);
CmFree(pszTmp);
pszTmp = m_pszParams;
m_pszParams = (LPTSTR) CmMalloc((dwLenPre + dwLenMid + dwLenPost + 1)*sizeof(TCHAR));
if (m_pszParams)
{
CopyMemory(m_pszParams, pszTmp, dwLenPre*sizeof(TCHAR)); // before %
lstrcatU(m_pszParams, pszMid); //append value
lstrcatU(m_pszParams, pszNextPercent+1); // after %
pszCurr = m_pszParams + dwLenPre + dwLenMid;
}
else
{
// we're out of memory
CMTRACE1(TEXT("ExpandMacros() malloc failed, can't strip off %% signs, GLE=%u."), GetLastError());
m_pszParams = pszTmp;
}
}
CmFree(pszMid);
}
CmFree(pszTmp);
}
else
{
pszCurr++;
}
}
else
{
pszCurr++;
}
}
}
#ifdef DEBUG
//+----------------------------------------------------------------------------
//
// Function: CAction::AssertValid
//
// Synopsis: For debug purpose only, assert the connection object is valid
//
// Arguments: None
//
// Returns: Nothing
//
// History: Created Header 2/12/98
//
//+----------------------------------------------------------------------------
void CAction::AssertValid() const
{
MYDBGASSERT(m_pszProgram && m_pszProgram[0]);
MYDBGASSERT(m_fIsDll == TRUE || m_fIsDll == FALSE);
}
#endif
//+----------------------------------------------------------------------------
//
// Function: CAction::ExpandEnvironmentStrings
//
// Synopsis: Utility fn to expand environment variables in the given string
//
// Arguments: ppsz - ptr to string (usually member variable)
//
// Returns: Nothing
//
// History: SumitC Created 29-Feb-2000
//
//+----------------------------------------------------------------------------
void CAction::ExpandEnvironmentStrings(LPTSTR * ppsz)
{
DWORD cLen;
MYDBGASSERT(*ppsz);
//
// find out how much memory we need to allocate
//
cLen = ExpandEnvironmentStringsU(*ppsz, NULL, 0);
if (cLen)
{
LPTSTR pszTemp = (LPTSTR) CmMalloc((cLen + 1) * sizeof(TCHAR));
if (pszTemp)
{
DWORD cLen2 = ExpandEnvironmentStringsU(*ppsz, pszTemp, cLen);
MYDBGASSERT(cLen == cLen2);
if (cLen2)
{
CmFree(*ppsz);
*ppsz = pszTemp;
}
}
}
}
//+----------------------------------------------------------------------------
//
// Function: CAction::IsAllowed
//
// Synopsis: checks Registry to see if a command is allowed to run
//
// Arguments: _ArgsStruct *pArgs - Ptr to global args struct
// LPDWORD lpdwLoadType - Ptr to DWORD to be filled with load type
//
// Returns: TRUE if action is allowed @ this time
//
// Notes: Checks SOFTWARE\Microsoft\Connection Manager\<ServiceName>
// Under which you will have the Values for each command
// 0 - system32 directory
// 1 - profile directory
// History: v-vijayb Created Header 7/20/99
//
//+----------------------------------------------------------------------------
BOOL CAction::IsAllowed(_ArgsStruct *pArgs, LPDWORD lpdwLoadType)
{
return IsActionEnabled(m_pszProgram, pArgs->szServiceName, pArgs->piniService->GetFile(), lpdwLoadType);
}
//+----------------------------------------------------------------------------
//
// Function: CAction::RunConnectActionForCurrentConnection
//
// Synopsis: This function compares the flags value of the connect action
// with the current connection type (from pArgs->GetTypeOfConnection).
// It returns TRUE if the connect action should be run for this type
// and FALSE if the connect action should be skipped.
//
// Arguments: _ArgsStruct *pArgs - Ptr to global args struct
//
// Returns: TRUE if action should be executed
//
// History: quintinb Created 04/20/00
//
//+----------------------------------------------------------------------------
BOOL CAction::RunConnectActionForCurrentConnection(_ArgsStruct *pArgs)
{
BOOL bReturn = TRUE;
DWORD dwType = pArgs->GetTypeOfConnection();
if (DIAL_UP_CONNECTION == dwType)
{
//
// Don't run direct only or tunnel connect actions
// on a dialup connection.
//
if ((m_dwFlags & DIRECT_ONLY) || (m_dwFlags & ALL_TUNNEL))
{
bReturn = FALSE;
}
}
else if (DIRECT_CONNECTION == dwType)
{
//
// Don't run dialup only or dialup connect actions
// on a direct connection.
//
if ((m_dwFlags & DIALUP_ONLY) || (m_dwFlags & ALL_DIALUP))
{
bReturn = FALSE;
}
}
else if (DOUBLE_DIAL_CONNECTION == dwType)
{
//
// Don't run dialup only or dialup connect actions
// on a direct connection.
//
if ((m_dwFlags & DIALUP_ONLY) || (m_dwFlags & DIRECT_ONLY))
{
bReturn = FALSE;
}
}
else
{
CMASSERTMSG(FALSE, TEXT("CActionList::Run -- unknown connection type, skipping action"));
bReturn = FALSE;
}
return bReturn;
}