372 lines
9.1 KiB
C++
372 lines
9.1 KiB
C++
|
|
||
|
//***********************************************************************
|
||
|
// remote.cpp
|
||
|
//
|
||
|
// This file contains code required to expand environment variables in the
|
||
|
// context of a remote machine. It does this by reading the environment variables
|
||
|
// from the remote machine's registry and caching them here.
|
||
|
//
|
||
|
// This file also contains code required to map local paths read out of the
|
||
|
// remote machine's registry into UNC paths such that c:\foo will be mapped
|
||
|
// to \\machine\c$\foo
|
||
|
//
|
||
|
// Author: Larry A. French
|
||
|
//
|
||
|
// History:
|
||
|
// 19-April-1996 Larry A. French
|
||
|
// Wrote it.
|
||
|
//
|
||
|
// Copyright (C) 1995, 1996 Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
//************************************************************************
|
||
|
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "remote.h"
|
||
|
#include "trapreg.h"
|
||
|
#include "regkey.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CEnvCache::CEnvCache()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
//*****************************************************************
|
||
|
// CEnvCache::GetEnvironmentVars
|
||
|
//
|
||
|
// Read the system environment variables for the remote machine out
|
||
|
// of its registry.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// LPCTSTR pszMachine
|
||
|
// Pointer to the remote machine's name.
|
||
|
//
|
||
|
// CMapStringToString* pmapVars
|
||
|
// This string to string map is where the environment variables
|
||
|
// for the machine are returned.
|
||
|
//
|
||
|
// Returns:
|
||
|
// SCODE
|
||
|
// S_OK if everything was successful, otherwise E_FAIL.
|
||
|
//
|
||
|
//****************************************************************
|
||
|
SCODE CEnvCache::GetEnvironmentVars(LPCTSTR pszMachine, CMapStringToString* pmapVars)
|
||
|
{
|
||
|
CRegistryKey regkey; // SYSTEM\CurrentControlSet\Services\EventLogs
|
||
|
CRegistryValue regval;
|
||
|
|
||
|
static TCHAR* apszNames1[] = {
|
||
|
_T("SourcePath"),
|
||
|
_T("SystemRoot")
|
||
|
};
|
||
|
|
||
|
if (regkey.Connect(pszMachine) != ERROR_SUCCESS) {
|
||
|
goto CONNECT_FAILURE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// First pick up the values for the SourcePath and SystemRoot environment variables and anything elese in
|
||
|
// apszNames1.
|
||
|
LONG nEntries;
|
||
|
LONG iEntry;
|
||
|
if (regkey.Open(_T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), KEY_READ ) == ERROR_SUCCESS) {
|
||
|
nEntries = sizeof(apszNames1) / sizeof(TCHAR*);
|
||
|
for (iEntry=0; iEntry<nEntries; ++iEntry) {
|
||
|
if (regkey.GetValue(apszNames1[iEntry], regval)) {
|
||
|
pmapVars->SetAt(apszNames1[iEntry], (LPCTSTR) regval.m_pData);
|
||
|
}
|
||
|
}
|
||
|
regkey.Close();
|
||
|
}
|
||
|
|
||
|
// Now get the rest of the environment variables.
|
||
|
if (regkey.Open(_T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"), KEY_READ ) == ERROR_SUCCESS) {
|
||
|
CStringArray* pasValues = regkey.EnumValues();
|
||
|
if (pasValues != NULL) {
|
||
|
nEntries = (LONG)pasValues->GetSize();
|
||
|
for (iEntry=0; iEntry< nEntries; ++iEntry) {
|
||
|
CString sValueName = pasValues->GetAt(iEntry);
|
||
|
if (regkey.GetValue(sValueName, regval)) {
|
||
|
pmapVars->SetAt(sValueName, (LPCTSTR) regval.m_pData);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
regkey.Close();
|
||
|
}
|
||
|
return S_OK;
|
||
|
|
||
|
CONNECT_FAILURE:
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
|
||
|
SCODE CEnvCache::AddMachine(LPCTSTR pszMachine)
|
||
|
{
|
||
|
CMapStringToString* pmapVars;
|
||
|
if (m_mapMachine.Lookup(pszMachine, (CObject*&) pmapVars)) {
|
||
|
// The machine already has an entry, so don't add another
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
pmapVars = new CMapStringToString;
|
||
|
m_mapMachine.SetAt(pszMachine, pmapVars);
|
||
|
|
||
|
SCODE sc = GetEnvironmentVars(pszMachine, pmapVars);
|
||
|
|
||
|
return sc;
|
||
|
}
|
||
|
|
||
|
|
||
|
//******************************************************************
|
||
|
// CEnvCache::Lookup
|
||
|
//
|
||
|
// Lookup an environment variable on the specified machine.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// LPCTSTR pszMachineName
|
||
|
// Pointer to the machine name string.
|
||
|
//
|
||
|
// LPCTSTR pszName
|
||
|
// Pointer to the name of the environment variable to lookup.
|
||
|
//
|
||
|
// CString& sValue
|
||
|
// This is a reference to the place where the environment varaible's
|
||
|
// value is returned.
|
||
|
//
|
||
|
//
|
||
|
// Returns:
|
||
|
// SCODE
|
||
|
// S_OK if the environment variable was found.
|
||
|
// E_FAIL if the environment varaible was not found.
|
||
|
//
|
||
|
//*******************************************************************
|
||
|
SCODE CEnvCache::Lookup(LPCTSTR pszMachineName, LPCTSTR pszName, CString& sResult)
|
||
|
{
|
||
|
SCODE sc;
|
||
|
CMapStringToString* pmapVars;
|
||
|
// Get a pointer to the machine's cached map of environment variable values.
|
||
|
// If the map hasn't been loaded yet, do so now and try to get its map again.
|
||
|
if (!m_mapMachine.Lookup(pszMachineName, (CObject*&) pmapVars)) {
|
||
|
sc = AddMachine(pszMachineName);
|
||
|
if (FAILED(sc)) {
|
||
|
return sc;
|
||
|
}
|
||
|
if (!m_mapMachine.Lookup(pszMachineName, (CObject*&) pmapVars)) {
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Look for the variable name in the environment name map
|
||
|
if (pmapVars->Lookup(pszName, sResult)) {
|
||
|
return S_OK;
|
||
|
}
|
||
|
else {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//****************************************************************
|
||
|
// RemoteExpandEnvStrings
|
||
|
//
|
||
|
// Epand a string that may contain environment variables in the
|
||
|
// context of a remote machine.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// LPCTSTR pszComputerName
|
||
|
// A pointer to the name of the remote machine.
|
||
|
//
|
||
|
// CEnvCache& cache
|
||
|
// The environment variable cache for all machines. Note: the
|
||
|
// cached values for a particular machine are loaded when there
|
||
|
// is a reference to the machine.
|
||
|
//
|
||
|
// CString& sValue
|
||
|
// The string to expand. This string is expanded in-place such
|
||
|
// that on return, the string will contain the expanded values.
|
||
|
//
|
||
|
// Returns:
|
||
|
// SCODE
|
||
|
// S_OK if all strings were expanded
|
||
|
//
|
||
|
//******************************************************************
|
||
|
SCODE RemoteExpandEnvStrings(LPCTSTR pszComputerName, CEnvCache& cache, CString& sValue)
|
||
|
{
|
||
|
SCODE sc = S_OK;
|
||
|
LPCTSTR psz = sValue;
|
||
|
TCHAR ch;
|
||
|
CString sEnvVarName;
|
||
|
CString sEnvVarValue;
|
||
|
CString sResult;
|
||
|
LPCTSTR pszPercent = NULL;
|
||
|
while (ch = *psz++) {
|
||
|
if (ch == _T('%')) {
|
||
|
pszPercent = psz - 1;
|
||
|
|
||
|
sEnvVarName = _T("");
|
||
|
while (ch = *psz) {
|
||
|
++psz;
|
||
|
if (ch == _T('%')) {
|
||
|
SCODE sc;
|
||
|
sc = cache.Lookup(pszComputerName, sEnvVarName, sEnvVarValue);
|
||
|
if (SUCCEEDED(sc)) {
|
||
|
sResult += sEnvVarValue;
|
||
|
pszPercent = NULL;
|
||
|
}
|
||
|
else {
|
||
|
// If any environment variable is not found, then fail.
|
||
|
sc = E_FAIL;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
if (iswspace(ch) || ch==_T(';')) {
|
||
|
break;
|
||
|
}
|
||
|
sEnvVarName += ch;
|
||
|
}
|
||
|
|
||
|
if (pszPercent != NULL) {
|
||
|
// Control comes here if the opening percent was not matched by a closing
|
||
|
// percent.
|
||
|
while(pszPercent < psz) {
|
||
|
sResult += *pszPercent++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
sResult += ch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sValue = sResult;
|
||
|
return sc;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//************************************************************
|
||
|
// SplitComplexPath
|
||
|
//
|
||
|
// Split a complex path consisting of several semicolon separated
|
||
|
// paths into separate paths and return them in a string array.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// LPCTSTR pszComplexPath
|
||
|
// Pointer to the path that may or may not be composed of
|
||
|
// several semicolon separated paths.
|
||
|
//
|
||
|
// CStringArray& saPath
|
||
|
// The place to return the split paths.
|
||
|
//
|
||
|
// Returns:
|
||
|
// The individual paths are returned via saPath
|
||
|
//
|
||
|
//*************************************************************
|
||
|
void SplitComplexPath(LPCTSTR pszComplexPath, CStringArray& saPath)
|
||
|
{
|
||
|
CString sPath;
|
||
|
while (*pszComplexPath) {
|
||
|
sPath.Empty();
|
||
|
while (isspace(*pszComplexPath)) {
|
||
|
++pszComplexPath;
|
||
|
}
|
||
|
|
||
|
while (*pszComplexPath &&
|
||
|
(*pszComplexPath != _T(';'))) {
|
||
|
sPath += *pszComplexPath++;
|
||
|
}
|
||
|
|
||
|
if (!sPath.IsEmpty()) {
|
||
|
saPath.Add(sPath);
|
||
|
}
|
||
|
|
||
|
if (*pszComplexPath==_T(';')) {
|
||
|
++pszComplexPath;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//**************************************************************************
|
||
|
// MapPathToUNC
|
||
|
//
|
||
|
// Map a path to the UNC equivallent. Note that this method assumes that
|
||
|
// for each path containing a drive letter that the target machine will have
|
||
|
// the path shared out. For example, if the path contains a "c:\foodir" prefix, then
|
||
|
// then you can get to "foodir" bygenerating the "\\machine\c$\foodir" path.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// LPCTSTR pszMachineName
|
||
|
// Pointer to the machine name.
|
||
|
//
|
||
|
// CString& sPath
|
||
|
// Pointer to the path to map. Upon return, this string will contain
|
||
|
// the mapped path.
|
||
|
//
|
||
|
// Returns:
|
||
|
// SCODE
|
||
|
// S_OK if successful
|
||
|
// E_FAIL if something went wrong.
|
||
|
//
|
||
|
//**************************************************************************
|
||
|
SCODE MapPathToUNC(LPCTSTR pszMachineName, CString& sPath)
|
||
|
{
|
||
|
CStringArray saPaths;
|
||
|
SplitComplexPath(sPath, saPaths);
|
||
|
sPath.Empty();
|
||
|
|
||
|
|
||
|
LPCTSTR pszPath = sPath.GetBuffer(sPath.GetLength() + 1);
|
||
|
LONG nPaths = (LONG)saPaths.GetSize();
|
||
|
SCODE sc = S_OK;
|
||
|
for (LONG iPath=0; iPath < nPaths; ++iPath) {
|
||
|
pszPath = saPaths[iPath];
|
||
|
|
||
|
if (isalpha(pszPath[0]) && pszPath[1]==_T(':')) {
|
||
|
CString sResult;
|
||
|
sResult += _T("\\\\");
|
||
|
sResult += pszMachineName;
|
||
|
sResult += _T('\\');
|
||
|
sResult += pszPath[0]; // Drive letter
|
||
|
sResult += _T("$\\");
|
||
|
pszPath += 2;
|
||
|
if (pszPath[0]==_T('\\')) {
|
||
|
++pszPath;
|
||
|
}
|
||
|
sResult += pszPath;
|
||
|
saPaths[iPath] = sResult;
|
||
|
}
|
||
|
else {
|
||
|
sc = E_FAIL;
|
||
|
}
|
||
|
sPath += saPaths[iPath];
|
||
|
if (iPath < nPaths - 1) {
|
||
|
sPath += _T("; ");
|
||
|
}
|
||
|
}
|
||
|
return sc;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|