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.
 
 
 
 
 
 

952 lines
26 KiB

/******************************************************************
Copyright (c) 2000-2002 Microsoft Corporation, All Rights Reserved
JOProcess.CPP -- WMI provider class implementation
******************************************************************/
#include "precomp.h"
#if NTONLY >= 5
#include "JOProcess.h"
#include <autoptr.h>
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
CJOProcess MyCJOProcess(
PROVIDER_NAME_WIN32NAMEDJOBOBJECTPROCESS,
IDS_CimWin32Namespace);
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
CJOProcess::CJOProcess(
LPCWSTR setName,
LPCWSTR pszNameSpace /*=NULL*/)
: Provider(setName, pszNameSpace)
{
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
CJOProcess::~CJOProcess()
{
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
HRESULT CJOProcess::GetObject(
CInstance* pInstance,
long lFlags /*= 0L*/ )
{
return FindSingleInstance(pInstance);
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
HRESULT CJOProcess::EnumerateInstances(
MethodContext* pMethodContext,
long lFlags)
{
HRESULT hr = WBEM_S_NO_ERROR;
hr = Enumerate(pMethodContext);
return hr;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
// We will only optimize for the
// case where a specific job was
// specified.
HRESULT CJOProcess::ExecQuery (
MethodContext *pMethodContext,
CFrameworkQuery& Query,
long lFlags
)
{
HRESULT hr = WBEM_S_NO_ERROR;
std::vector<_bstr_t> rgJOs;
DWORD dwJOsCount = 0L;
Query.GetValuesForProp(L"Collection", rgJOs);
dwJOsCount = rgJOs.size();
if(dwJOsCount > 0)
{
CInstancePtr pInstJO;
CHString chstrPath;
for(DWORD x = 0; x < dwJOsCount; x++)
{
// First we see if the specified JO exists.
chstrPath.Format(
L"\\\\.\\%s:%s",
IDS_CimWin32Namespace,
(LPCWSTR)rgJOs[x]);
hr = CWbemProviderGlue::GetInstanceKeysByPath(
chstrPath,
&pInstJO,
pMethodContext);
if (SUCCEEDED(hr))
{
// Ok, the JO exists. Enumerate its processes...
// rgJOs[x] contains something like
// Win32_NamedJobObject.CollectionID="myjob",
// from which I want just the myjob part.
CHString chstrInstKey;
if(GetInstKey(
CHString((LPCWSTR)rgJOs[x]),
chstrInstKey))
{
hr = EnumerateProcsInJob(
chstrInstKey,
pMethodContext);
if (FAILED(hr))
{
break;
}
}
else
{
return WBEM_E_INVALID_PARAMETER;
}
}
}
}
else
{
hr = Enumerate(pMethodContext);
}
return hr;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
HRESULT CJOProcess::PutInstance (
const CInstance &Instance,
long lFlags
)
{
HRESULT hr = WBEM_E_INVALID_PARAMETER;
MethodContext *pMethodContext = Instance.GetMethodContext();
long lCreateFlags = lFlags & 3;
// Decide how to proceed based on the value of lFlags:
// (we want to support PutInstance in all cases except
// where the client asked to update the instance).
if(lCreateFlags != WBEM_FLAG_UPDATE_ONLY)
{
// The caller only wants to create an instance that doesn't exist.
if((hr = FindSingleInstance(
&Instance)) == WBEM_E_NOT_FOUND)
{
// The association instance does not already exist, so create it...
// First see that the job object instance exists...
CHString chstrJOPath;
if ( ! Instance.GetCHString(L"Collection", chstrJOPath) )
{
return WBEM_E_FAILED ;
}
CInstancePtr pJOInst;
hr = CWbemProviderGlue::GetInstanceKeysByPath(
chstrJOPath,
&pJOInst,
pMethodContext);
if (SUCCEEDED(hr))
{
// Confirm that the process exists...
CHString chstrProcPath;
if ( ! Instance.GetCHString(L"Member", chstrProcPath) )
{
return WBEM_E_FAILED ;
}
CInstancePtr pProcInst;
hr = CWbemProviderGlue::GetInstanceKeysByPath(
chstrProcPath,
&pProcInst,
pMethodContext);
if(SUCCEEDED(hr))
{
hr = Create(pJOInst, pProcInst);
}
}
}
}
return hr;
}
/*****************************************************************************
*
* FUNCTION : CJOProcess::FindSingleInstance
*
* DESCRIPTION : Internal helper function used to locate a single job
* object.
*
* INPUTS : A pointer to a CInstance containing the instance we are
* attempting to locate and fill values for.
*
* RETURNS : A valid HRESULT
*
*****************************************************************************/
HRESULT CJOProcess::FindSingleInstance (
const CInstance* pInstance
)
{
HRESULT hr = WBEM_S_NO_ERROR;
if(!pInstance)
{
return WBEM_E_INVALID_PARAMETER;
}
MethodContext* pMethodContext = pInstance->GetMethodContext();
CHString chstrCollection;
CHString chstrMember;
// Find out which JO and which process are specified...
if ( ! pInstance->GetCHString(L"Collection", chstrCollection) )
{
return WBEM_E_FAILED ;
}
if ( ! pInstance->GetCHString(L"Member", chstrMember) )
{
return WBEM_E_FAILED ;
}
CHString chstrCollectionID;
CHString chstrProcessHandle;
CInstancePtr cinstJO;
CInstancePtr cinstProcess;
if(GetInstKey(chstrCollection, chstrCollectionID) &&
GetInstKey(chstrMember, chstrProcessHandle))
{
// See if the specified job exists...
hr = CWbemProviderGlue::GetInstanceKeysByPath(
chstrCollection,
&cinstJO,
pMethodContext);
if(SUCCEEDED(hr))
{
// See if the specified process exists...
hr = CWbemProviderGlue::GetInstanceKeysByPath(
chstrMember,
&cinstProcess,
pMethodContext);
}
if(SUCCEEDED(hr))
{
// The endpoints exist. Is the specified
// process part of the specified job though?
CHString chstrProcessID;
DWORD dwProcessID;
if(cinstProcess->GetCHString(L"Handle", chstrProcessID))
{
dwProcessID = _wtoi(chstrProcessID);
SmartCloseHandle hJob;
CHString chstrUndecoratedJOName;
UndecorateJOName(
chstrCollectionID,
chstrUndecoratedJOName);
hJob = ::OpenJobObject(
MAXIMUM_ALLOWED,
FALSE,
chstrUndecoratedJOName);
if(hJob != NULL)
{
long lSize = 0L;
bool fGotProcList = false;
DWORD dwLen = 0L;
lSize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + (5 * sizeof(ULONG_PTR));
wmilib::auto_buffer < BYTE > pbBuff ( new BYTE [ lSize ], lSize ) ;
if ( pbBuff.get () )
{
fGotProcList = ::QueryInformationJobObject(
hJob,
JobObjectBasicProcessIdList,
pbBuff.get (),
lSize,
&dwLen);
if(!fGotProcList)
{
// need to grow the buffer...
lSize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) +
(((JOBOBJECT_BASIC_PROCESS_ID_LIST*)pbBuff.get ())->NumberOfAssignedProcesses - 1)*sizeof(ULONG_PTR);
pbBuff.reset ( new BYTE [ lSize ] ) ;
if ( pbBuff.get () )
{
fGotProcList = ::QueryInformationJobObject(
hJob,
JobObjectBasicProcessIdList,
pbBuff.get (),
lSize,
&dwLen);
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
if(fGotProcList)
{
PJOBOBJECT_BASIC_PROCESS_ID_LIST pjobpl = static_cast<PJOBOBJECT_BASIC_PROCESS_ID_LIST>(static_cast<PVOID>(pbBuff.get ()));
bool fExists = false;
for(long m = 0;
m < pjobpl->NumberOfProcessIdsInList && !fExists;
m++)
{
if(dwProcessID == pjobpl->ProcessIdList[m])
{
fExists = true;
}
}
// If the process wasn't in the job,
// we didn't find an instance of the
// requested association, even though
// the endpoints may have existed.
if(!fExists)
{
hr = WBEM_E_NOT_FOUND;
}
}
else
{
hr = WinErrorToWBEMhResult(::GetLastError());
}
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
hr = WinErrorToWBEMhResult(::GetLastError());
}
}
else
{
hr = WBEM_E_INVALID_PARAMETER;
}
}
}
else
{
hr = WBEM_E_FAILED;
}
return hr;
}
/*****************************************************************************
*
* FUNCTION : CJOProcess::Create
*
* DESCRIPTION : Internal helper function used to add a process to a job.
*
* INPUTS : A pointer to the JO instance to add the proc to, and
* a pointer to the proc instance to add
*
* RETURNS : A valid HRESULT.
*
*****************************************************************************/
HRESULT CJOProcess::Create (
const CInstance &JOInstance,
const CInstance &ProcInstance
)
{
HRESULT hr = WBEM_S_NO_ERROR;
CHString chstrJOID;
CHString chstrProcHandle;
// JO to add the proc to...
if ( ! JOInstance.GetCHString(L"CollectionID", chstrJOID) )
{
return WBEM_E_FAILED ;
}
// Proc to add to the job...
if ( ! ProcInstance.GetCHString(L"Handle", chstrProcHandle) )
{
return WBEM_E_FAILED ;
}
DWORD dwProcID = _wtol(chstrProcHandle);
// Do the add
SmartCloseHandle hJob;
CHString chstrUndecoratedJOName;
UndecorateJOName(
chstrJOID,
chstrUndecoratedJOName);
hJob = ::OpenJobObject(
MAXIMUM_ALLOWED,
FALSE,
chstrUndecoratedJOName);
if(hJob != NULL)
{
SmartCloseHandle hProc;
hProc = ::OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
dwProcID);
if(hProc != NULL)
{
if(!::AssignProcessToJobObject(
hJob,
hProc))
{
hr = MAKE_SCODE(
SEVERITY_ERROR,
FACILITY_WIN32,
GetLastError());
}
}
}
else
{
hr = WinErrorToWBEMhResult(::GetLastError());
}
return hr;
}
/*****************************************************************************
*
* FUNCTION : CJOProcess::Enumerate
*
* DESCRIPTION : Internal helper function used to enumerate instances of
* this class. All instances are enumerated, but only the
* properties specified are obtained.
*
* INPUTS : A pointer to a the MethodContext for the call.
* A DWORD specifying which properties are requested.
*
* RETURNS : A valid HRESULT
*
*****************************************************************************/
HRESULT CJOProcess::Enumerate (
MethodContext *pMethodContext
)
{
HRESULT hr = WBEM_S_NO_ERROR;
TRefPointerCollection<CInstance> JOList;
hr = CWbemProviderGlue::GetInstancesByQuery(
L"SELECT CollectionID FROM Win32_NamedJobObject",
&JOList,
pMethodContext,
IDS_CimWin32Namespace);
if(SUCCEEDED(hr))
{
REFPTRCOLLECTION_POSITION pos;
// Initialize the enum
if(JOList.BeginEnum(pos))
{
// Set some vars
CHString chstrJOID;
CInstancePtr pJOInst;
for (pJOInst.Attach(JOList.GetNext(pos)) ;
(pJOInst != NULL) ;
pJOInst.Attach(JOList.GetNext(pos)) )
{
bool t_Status = pJOInst->GetCHString (
L"CollectionID",
chstrJOID
) ;
if ( t_Status )
{
hr = EnumerateProcsInJob (
chstrJOID,
pMethodContext
);
}
else
{
hr = WBEM_E_FAILED ;
}
}
}
}
return hr;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
HRESULT CJOProcess::EnumerateProcsInJob (
LPCWSTR wstrJobID,
MethodContext *pMethodContext
)
{
HRESULT hr = WBEM_S_NO_ERROR;
SmartCloseHandle hJob;
CHString chstrUndecoratedJOName;
UndecorateJOName(
wstrJobID,
chstrUndecoratedJOName);
hJob = ::OpenJobObject(
MAXIMUM_ALLOWED,
FALSE,
chstrUndecoratedJOName);
if(hJob != NULL)
{
long lSize = 0L;
bool fGotProcList = false;
DWORD dwLen = 0L;
lSize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + (5 * sizeof(ULONG_PTR));
wmilib::auto_buffer < BYTE > pbBuff ( new BYTE [ lSize ], lSize ) ;
if ( pbBuff.get () )
{
fGotProcList = ::QueryInformationJobObject(
hJob,
JobObjectBasicProcessIdList,
pbBuff.get (),
lSize,
&dwLen);
if(!fGotProcList)
{
// need to grow the buffer...
lSize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) +
(((JOBOBJECT_BASIC_PROCESS_ID_LIST*)pbBuff.get ())->NumberOfAssignedProcesses - 1)*sizeof(ULONG_PTR);
pbBuff.reset ( new BYTE [ lSize ] ) ;
if ( pbBuff.get () )
{
fGotProcList = ::QueryInformationJobObject(
hJob,
JobObjectBasicProcessIdList,
pbBuff.get (),
lSize,
&dwLen);
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
if(fGotProcList)
{
PJOBOBJECT_BASIC_PROCESS_ID_LIST pjobpl = static_cast<PJOBOBJECT_BASIC_PROCESS_ID_LIST>(static_cast<PVOID>(pbBuff.get ()));
for(long m = 0;
m < pjobpl->NumberOfProcessIdsInList;
m++)
{
// Create association inst for each
// proc in the job...
CInstancePtr pInstance(CreateNewInstance(pMethodContext),
false);
// Set the endpoints...
CHString chstrEscaped;
DecorateJOName(chstrUndecoratedJOName, chstrEscaped);
EscapeBackslashes(chstrEscaped, chstrEscaped);
EscapeQuotes(chstrEscaped, chstrEscaped);
CHString chstrTmp;
chstrTmp.Format(L"\\\\.\\%s:Win32_NamedJobObject.CollectionID=\"%s\"",
IDS_CimWin32Namespace,
(LPCWSTR)chstrEscaped);
pInstance->SetCHString(L"Collection", chstrTmp);
CHString chstrHandle;
chstrHandle.Format(L"%d", pjobpl->ProcessIdList[m]);
chstrTmp.Format(L"\\\\.\\%s:Win32_Process.Handle=\"%s\"",
IDS_CimWin32Namespace,
(LPCWSTR) chstrHandle);
pInstance->SetCHString(L"Member", chstrTmp);
if (SUCCEEDED(hr))
{
hr = pInstance->Commit();
}
}
}
else
{
hr = WinErrorToWBEMhResult(::GetLastError());
}
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
hr = WinErrorToWBEMhResult(::GetLastError());
}
return hr;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
bool CJOProcess::GetInstKey (
CHString& chstrInstPath,
CHString& chstrKeyName
)
{
// the object path is specified in
// the first arg. It should at a
// minimum always contain an '=' sign,
// after which, in quotes is the
// object key.
bool fRet = false;
CHString chstrTmp;
LONG lPos = chstrInstPath.Find(L'=');
if(lPos != -1)
{
chstrTmp = chstrInstPath.Mid(lPos + 1);
// Remove quotes...
if(chstrTmp.Left(1) == L"\"")
{
chstrTmp = chstrTmp.Mid(1);
if(chstrTmp.Right(1) == L"\"")
{
chstrTmp = chstrTmp.Left(chstrTmp.GetLength() - 1);
chstrKeyName = chstrTmp;
fRet = true;
}
}
}
return fRet;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
// Takes a decorated job object name and
// undecorates it. Decorated job object names
// have a backslash preceeding any character
// that should be uppercase once undecorated.
//
// Due to the way CIMOM handles backslashes,
// we will get capital letters preceeded by
// two, not just one, backslashes. Hence, we
// must strip them both.
//
// According to the decoration scheme, the
// following are both lower case: 'A' and 'a',
// while the following are both upper case:
// '\a' and '\A'.
//
void CJOProcess::UndecorateJOName (
LPCWSTR wstrDecoratedName,
CHString& chstrUndecoratedJOName
)
{
if(wstrDecoratedName != NULL &&
*wstrDecoratedName != L'\0')
{
LPWSTR wstrDecoratedNameLower = NULL;
try
{
wstrDecoratedNameLower = new WCHAR[wcslen(wstrDecoratedName)+1];
if(wstrDecoratedNameLower)
{
wcscpy(wstrDecoratedNameLower, wstrDecoratedName);
_wcslwr(wstrDecoratedNameLower);
WCHAR* p3 = chstrUndecoratedJOName.GetBuffer(
wcslen(wstrDecoratedNameLower) + 1);
const WCHAR* p1 = wstrDecoratedNameLower;
const WCHAR* p2 = p1 + 1;
while(*p1 != L'\0')
{
if(*p1 == L'\\')
{
if(*p2 != NULL)
{
// Might have any number of
// backslashes back to back,
// which we will treat as
// being the same as one
// backslash - i.e., we will
// skip over the backslash(s)
// and copy over the following
// letter.
while(*p2 == L'\\')
{
p2++;
};
*p3 = towupper(*p2);
p3++;
p1 = p2 + 1;
if(*p1 != L'\0')
{
p2 = p1 + 1;
}
}
else
{
p1++;
}
}
else
{
*p3 = *p1;
p3++;
p1 = p2;
if(*p1 != L'\0')
{
p2 = p1 + 1;
}
}
}
*p3 = NULL;
chstrUndecoratedJOName.ReleaseBuffer();
delete wstrDecoratedNameLower;
wstrDecoratedNameLower = NULL;
}
}
catch(...)
{
if(wstrDecoratedNameLower)
{
delete wstrDecoratedNameLower;
wstrDecoratedNameLower = NULL;
}
throw;
}
}
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
// Does the inverse of the above function.
// However, here, we only need to put in one
// backslash before each uppercase letter.
// CIMOM will add the second backslash.
void CJOProcess::DecorateJOName (
LPCWSTR wstrUndecoratedName,
CHString& chstrDecoratedJOName
)
{
if(wstrUndecoratedName != NULL &&
*wstrUndecoratedName != L'\0')
{
// Worst case is that we will have
// a decorated string twice as long
// as the undecorated string (happens
// is every character in the undecorated
// string is a capital letter).
WCHAR* p3 = chstrDecoratedJOName.GetBuffer(
2 * (wcslen(wstrUndecoratedName) + 1));
const WCHAR* p1 = wstrUndecoratedName;
while(*p1 != L'\0')
{
if(iswupper(*p1))
{
// Add in a backslash...
*p3 = L'\\';
p3++;
// Add in the character...
*p3 = *p1;
p3++;
p1++;
}
else
{
// Add in the character...
*p3 = *p1;
p3++;
p1++;
}
}
*p3 = NULL;
chstrDecoratedJOName.ReleaseBuffer();
// What if we had a job called Job,
// and someone specified it in the
// object path as "Job" instead of
// "\Job"? We DON'T want to find it
// in such a case, because this would
// appear to not be adhering to our
// own convention. Hence, we
// lowercase the incoming string.
chstrDecoratedJOName.MakeLower();
}
}
#endif // #if NTONLY >= 5