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.
 
 
 
 
 
 

1009 lines
29 KiB

// Copyright (c) 2000-2002 Microsoft Corporation, All Rights Reserved
// Helpers.cpp: Helper functions for the SecUtil component
//#include "FWCommon.h"
//#include <windows.h>
//#include <winnt.h>
/*
#ifndef USE_POLARITY
// For most users, this is the correct setting for POLARITY.
#define USE_POLARITY
#endif
*/
#include "precomp.h"
#include <cominit.h>
#include <vector>
#include "Helpers.h"
#include "AssertBreak.h"
#include "CVARIANT.H"
#include <crtdbg.h>
#define IDS_NTDLLDOTDLL L"NTDLL.DLL"
#define IDS_NTOPENDIRECTORYOBJECT "NtOpenDirectoryObject"
#define IDS_NTQUERYDIRECTORYOBJECT "NtQueryDirectoryObject"
#define IDS_RTLINITUNICODESTRING "RtlInitUnicodeString"
#define IDS_WHACKWHACKBASENAMEDOBJECTS L"\\BaseNamedObjects"
#define IDS_NTQUERYINFORMATIONPROCESS "NtQueryInformationProcess"
#define IDS_NTOPENPROCESS "NtOpenProcess"
#define IDS_WIN32_ERROR_CODE L"Win32ErrorCode"
#define IDS_ADDITIONAL_DESCRIPTION L"AdditionalDescription"
#define IDS_OPERATION L"Operation"
typedef NTSTATUS (NTAPI *PFN_NT_OPEN_DIRECTORY_OBJECT)
(
OUT PHANDLE DirectoryHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
typedef NTSTATUS (NTAPI *PFN_NT_QUERY_DIRECTORY_OBJECT)
(
IN HANDLE DirectoryHandle,
OUT PVOID Buffer,
IN ULONG Length,
IN BOOLEAN ReturnSingleEntry,
IN BOOLEAN RestartScan,
IN OUT PULONG Context,
OUT PULONG ReturnLength OPTIONAL
);
typedef VOID (WINAPI *PFN_NTDLL_RTL_INIT_UNICODE_STRING)
(
OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);
typedef NTSTATUS (NTAPI *PFN_NTDLL_NT_QUERY_INFORMATION_PROCESS)
(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
typedef NTSTATUS (NTAPI *PFN_NT_OPEN_PROCESS)
(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId OPTIONAL
);
//***************************************************************************
//
// CreateInst
//
// Purpose: Creates a new instance.
//
// Return: S_OK if all is well, otherwise an error code is returned
//
//***************************************************************************
HRESULT CreateInst(
IWbemServices *pNamespace,
IWbemClassObject **pNewInst,
BSTR bstrClassName,
IWbemContext *pCtx)
{
HRESULT hr = S_OK;
IWbemClassObjectPtr pClass;
hr = pNamespace->GetObject(
bstrClassName,
0,
pCtx,
&pClass,
NULL);
if(SUCCEEDED(hr))
{
hr = pClass->SpawnInstance(
0,
pNewInst);
}
return hr;
}
//***************************************************************************
//
// GetObjInstKeyVal
//
// Purpose: Obtains an object's instance key from an object path.
//
// Return: true if the key was obtained.
//
//***************************************************************************
HRESULT GetObjInstKeyVal(
const BSTR ObjectPath,
LPCWSTR wstrClassName,
LPCWSTR wstrKeyPropName,
LPWSTR wstrObjInstKeyVal,
long lBufLen)
{
HRESULT hr = WBEM_S_NO_ERROR;
WCHAR* pwcEqualSign = NULL;
WCHAR* pwcTmp = NULL;
if(!ObjectPath)
{
return WBEM_E_INVALID_PARAMETER;
}
if((pwcEqualSign = wcschr(ObjectPath, L'=')) != NULL)
{
pwcEqualSign++;
long lLen = wcslen(pwcEqualSign) * sizeof(WCHAR);
if(*pwcEqualSign &&
lLen > 0 &&
lLen < (long)(lBufLen - sizeof(WCHAR)))
{
wcscpy(wstrObjInstKeyVal, pwcEqualSign);
// Remove any quotation marks that might
// be there...
RemoveQuotes(wstrObjInstKeyVal);
// Also need to check that the class name
// matches the name specified...
WCHAR wstrClass[_MAX_PATH];
wcscpy(wstrClass, ObjectPath);
pwcTmp = wcschr(wstrClass, L'=');
if(pwcTmp)
{
*pwcTmp = '\0';
// Either the key property was specified or
// it wasn't...
pwcTmp = NULL;
pwcTmp = wcschr(wstrClass, L'.');
if(pwcTmp)
{
// Key property specified, so check that
// both it and the class name are correct...
*pwcTmp = '\0';
if(_wcsicmp(wstrClassName, wstrClass) == 0)
{
if(_wcsicmp(wstrKeyPropName, ++pwcTmp) != 0)
{
hr = WBEM_E_INVALID_PARAMETER;
}
}
else
{
hr = WBEM_E_INVALID_CLASS;
}
}
else
{
// No key prop specified, so only need
// to check that the class name is correct...
if(_wcsicmp(wstrClassName, wstrClass) != 0)
{
hr = WBEM_E_INVALID_CLASS;
}
}
}
else
{
hr = WBEM_E_INVALID_PARAMETER;
}
}
else
{
hr = WBEM_E_INVALID_PARAMETER;
}
}
else
{
hr = WBEM_E_INVALID_PARAMETER;
}
return hr;
}
HRESULT GetJobObjectList(
std::vector<_bstr_t>& rgbstrtJOs)
{
HRESULT hr = S_OK;
HINSTANCE hinst = NULL;
SmartCloseHANDLE hDir;
PBYTE pbBuff = NULL;
try
{
if((hinst = ::LoadLibrary(IDS_NTDLLDOTDLL)) != NULL)
{
PFN_NT_OPEN_DIRECTORY_OBJECT pfnNtOpenDirectoryObject = NULL;
PFN_NT_QUERY_DIRECTORY_OBJECT pfnNtQueryDirectoryObject = NULL;
PFN_NTDLL_RTL_INIT_UNICODE_STRING pfnRtlInitUnicodeString = NULL;
pfnNtOpenDirectoryObject = (PFN_NT_OPEN_DIRECTORY_OBJECT)
::GetProcAddress(hinst, IDS_NTOPENDIRECTORYOBJECT);
pfnNtQueryDirectoryObject = (PFN_NT_QUERY_DIRECTORY_OBJECT)
::GetProcAddress(hinst, IDS_NTQUERYDIRECTORYOBJECT);
pfnRtlInitUnicodeString = (PFN_NTDLL_RTL_INIT_UNICODE_STRING)
::GetProcAddress(hinst, IDS_RTLINITUNICODESTRING);
if(pfnNtOpenDirectoryObject != NULL &&
pfnNtQueryDirectoryObject != NULL &&
pfnRtlInitUnicodeString != NULL)
{
OBJECT_ATTRIBUTES oaAttributes;
UNICODE_STRING ustrNtFileName;
NTSTATUS ntstat = -1L;
pfnRtlInitUnicodeString(&ustrNtFileName,
IDS_WHACKWHACKBASENAMEDOBJECTS);
InitializeObjectAttributes(&oaAttributes,
&ustrNtFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
ntstat = pfnNtOpenDirectoryObject(&hDir,
FILE_READ_DATA,
&oaAttributes);
if(NT_SUCCESS(ntstat))
{
ULONG ulContext = -1L;
ntstat = STATUS_SUCCESS;
ULONG ulBufLen = 0L;
ULONG ulNewBufLen = 0L;
// First query to get buffer size to allocate...
ntstat = pfnNtQueryDirectoryObject(hDir, // IN HANDLE DirectoryHandle,
NULL, // OUT PVOID Buffer,
0L, // IN ULONG Length,
FALSE, // IN BOOLEAN ReturnSingleEntry,
TRUE, // IN BOOLEAN RestartScan,
&ulContext, // IN OUT PULONG Context,
&ulBufLen); // OUT PULONG ReturnLength OPTIONAL
pbBuff = new BYTE[ulBufLen];
if(pbBuff)
{
// then loop through all the entries...
for(; ntstat != STATUS_NO_MORE_ENTRIES && pbBuff != NULL;)
{
ntstat = pfnNtQueryDirectoryObject(hDir, // IN HANDLE DirectoryHandle,
pbBuff, // OUT PVOID Buffer,
ulBufLen, // IN ULONG Length,
TRUE, // IN BOOLEAN ReturnSingleEntry,
FALSE, // IN BOOLEAN RestartScan,
&ulContext, // IN OUT PULONG Context,
&ulNewBufLen); // OUT PULONG ReturnLength OPTIONAL
if(ntstat == STATUS_BUFFER_TOO_SMALL)
{
// Deallocate buffer and reallocate...
if(pbBuff != NULL)
{
delete pbBuff;
pbBuff = NULL;
}
pbBuff = new BYTE[ulNewBufLen];
ulBufLen = ulNewBufLen;
}
else if(NT_SUCCESS(ntstat))
{
// All went well, should have data...
if(pbBuff != NULL)
{
POBJECT_DIRECTORY_INFORMATION podi = (POBJECT_DIRECTORY_INFORMATION) pbBuff;
LPWSTR wstrName = (LPWSTR)podi->Name.Buffer;
LPWSTR wstrType = (LPWSTR)podi->TypeName.Buffer;
// do something...
// offset to string name is in four bytes...
if(wstrName != NULL &&
wstrType != NULL &&
wcslen(wstrType) == 3)
{
WCHAR wstrTmp[4]; wstrTmp[3] = '\0';
wcsncpy(wstrTmp, wstrType, 3);
if(_wcsicmp(wstrTmp, L"job") == 0)
{
rgbstrtJOs.push_back(_bstr_t(wstrName));
}
}
}
}
else if(ntstat == STATUS_NO_MORE_ENTRIES)
{
// we will break
}
else
{
// Something we weren't expecting happened, so bail out...
hr = E_FAIL;
}
} // while we still have entries
delete pbBuff;
pbBuff = NULL;
}
else
{
hr = E_OUTOFMEMORY;
}
} // NtOpenDirectoryObject succeeded
else
{
hr = E_FAIL;
}
} // Got the fn ptrs
else
{
hr = E_FAIL;
}
::FreeLibrary(hinst);
}
else
{
hr = E_FAIL;
}
}
catch(...)
{
if(pbBuff != NULL)
{
delete pbBuff; pbBuff = NULL;
}
if(hinst != NULL)
{
::FreeLibrary(hinst); hinst = NULL;
}
throw;
}
return hr;
}
void StringFromSid(PSID psid, _bstr_t& strSID)
{
// Initialize m_strSid - human readable form of our SID
SID_IDENTIFIER_AUTHORITY *psia = NULL;
psia = ::GetSidIdentifierAuthority(psid);
WCHAR wstrTmp[_MAX_PATH];
// We assume that only last byte is used
// (authorities between 0 and 15).
// Correct this if needed.
ASSERT( psia->Value[0] ==
psia->Value[1] ==
psia->Value[2] ==
psia->Value[3] ==
psia->Value[4] == 0 );
DWORD dwTopAuthority = psia->Value[5];
wsprintf(wstrTmp, L"S-1-%u", dwTopAuthority);
WCHAR wstrSubAuthority[_MAX_PATH];
int iSubAuthorityCount = *(GetSidSubAuthorityCount(psid));
for ( int i = 0; i < iSubAuthorityCount; i++ ) {
DWORD dwSubAuthority = *(GetSidSubAuthority(psid, i));
wsprintf(wstrSubAuthority, L"%u", dwSubAuthority);
wcscat(wstrTmp, L"-");
wcscat(wstrTmp, wstrSubAuthority);
}
strSID = wstrTmp;
}
void RemoveQuotes(LPWSTR wstrObjInstKeyVal)
{
WCHAR wstrTmp[MAX_PATH] = { L'\0' };
WCHAR* pwchr = NULL;
// Get rid of the first quote...
if((pwchr = wcschr(wstrObjInstKeyVal, L'"')) != NULL)
{
wcscpy(wstrTmp, pwchr+1);
}
// now the last...
if((pwchr = wcsrchr(wstrTmp, L'"')) != NULL)
{
*pwchr = L'\0';
}
wcscpy(wstrObjInstKeyVal, wstrTmp);
}
HRESULT CheckImpersonationLevel()
{
HRESULT hr = WBEM_E_ACCESS_DENIED;
OSVERSIONINFOW OsVersionInfoW;
OsVersionInfoW.dwOSVersionInfoSize = sizeof (OSVERSIONINFOW);
GetVersionExW(&OsVersionInfoW);
if (OsVersionInfoW.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
HRESULT hRes = WbemCoImpersonateClient();
if (SUCCEEDED(hRes)) // From cominit.cpp - needed for nt3.51
{
// Now, let's check the impersonation level. First, get the thread token
SmartCloseHANDLE hThreadTok;
DWORD dwImp, dwBytesReturned;
if (!OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY,
TRUE,
&hThreadTok
))
{
DWORD dwLastError = GetLastError();
if (dwLastError == ERROR_NO_TOKEN)
{
// If the CoImpersonate works, but the OpenThreadToken fails due to ERROR_NO_TOKEN, we
// are running under the process token (either local system, or if we are running
// with /exe, the rights of the logged in user). In either case, impersonation rights
// don't apply. We have the full rights of that user.
hr = WBEM_S_NO_ERROR;
}
else
{
// If we failed to get the thread token for any other reason, an error.
hr = WBEM_E_ACCESS_DENIED;
}
}
else
{
// We really do have a thread token, so let's retrieve its level
if (GetTokenInformation(
hThreadTok,
TokenImpersonationLevel,
&dwImp,
sizeof(DWORD),
&dwBytesReturned
))
{
// Is the impersonation level Impersonate?
if ((dwImp == SecurityImpersonation) || (dwImp == SecurityDelegation))
{
hr = WBEM_S_NO_ERROR;
}
else
{
hr = WBEM_E_ACCESS_DENIED;
}
}
else
{
hr = WBEM_E_FAILED;
}
}
if (FAILED(hr))
{
WbemCoRevertToSelf();
}
}
else if (hRes == E_NOTIMPL)
{
// On 3.51 or vanilla 95, this call is not implemented, we should work anyway
hr = WBEM_S_NO_ERROR;
}
}
else
{
// let win9X in...
hr = WBEM_S_NO_ERROR;
}
return hr;
}
HRESULT SetStatusObject(
IWbemContext* pCtx,
IWbemServices* pSvcs,
DWORD dwError,
LPCWSTR wstrErrorDescription,
LPCWSTR wstrOperation,
LPCWSTR wstrNamespace,
IWbemClassObject** ppStatusObjOut)
{
HRESULT hr = WBEM_S_NO_ERROR;
IWbemClassObject* pStatusObj = NULL;
ASSERT_BREAK(pCtx != NULL);
ASSERT_BREAK(pSvcs != NULL);
if(pSvcs && ppStatusObjOut && pCtx)
{
pStatusObj = GetStatusObject(
pCtx,
pSvcs);
if(pStatusObj != NULL)
{
CVARIANT v;
// Set the error code:
v.SetLONG(dwError);
pStatusObj->Put(
IDS_WIN32_ERROR_CODE,
0,
&v,
NULL);
v.Clear();
// Set the error description
if(wstrErrorDescription != NULL &&
*wstrErrorDescription != L'\0')
{
v.SetStr(wstrErrorDescription);
pStatusObj->Put(
IDS_ADDITIONAL_DESCRIPTION,
0,
&v,
NULL);
v.Clear();
}
if(wstrOperation != NULL &&
*wstrOperation != L'\0')
{
v.SetStr(wstrOperation);
pStatusObj->Put(
IDS_OPERATION,
0,
&v,
NULL);
v.Clear();
}
}
if(pStatusObj)
{
if(*ppStatusObjOut != NULL)
{
(*ppStatusObjOut)->Release();
*ppStatusObjOut = NULL;
}
*ppStatusObjOut = pStatusObj;
}
else
{
hr = WBEM_E_FAILED;
}
}
else
{
hr = WBEM_E_FAILED;
}
return hr;
}
IWbemClassObject* GetStatusObject(
IWbemContext* pContext,
IWbemServices* pSrvc)
{
ASSERT_BREAK(pContext != NULL);
ASSERT_BREAK(pSrvc != NULL);
IWbemClassObjectPtr pStatusObjClass;
IWbemClassObject* pStatusObjectInstance = NULL;
if(pContext && pSrvc)
{
if(pSrvc)
{
// not checking return code, error object should be NULL on error
pSrvc->GetObject(
_bstr_t(JOB_OBJECT_STATUS_OBJECT),
0,
pContext,
&pStatusObjClass,
NULL);
if(pStatusObjClass)
{
pStatusObjClass->SpawnInstance(
0,
&pStatusObjectInstance);
}
}
}
ASSERT_BREAK(pStatusObjectInstance);
return pStatusObjectInstance;
}
void UndecorateNamesInNamedJONameList(
std::vector<_bstr_t>& rgNamedJOs)
{
std::vector<_bstr_t> rgUndecoratedNames;
CHString chstrTemp;
for(long m = 0L;
m < rgNamedJOs.size();
m++)
{
UndecorateJOName(
rgNamedJOs[m],
chstrTemp);
_bstr_t bstrtTemp((LPCWSTR)chstrTemp);
rgUndecoratedNames.push_back(
bstrtTemp);
}
// Wipe out the original vector...
rgNamedJOs.clear();
// Push in new vector's contents...
for(m = 0L;
m < rgUndecoratedNames.size();
m++)
{
rgNamedJOs.push_back(
rgUndecoratedNames[m]);
}
}
// 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 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;
}
}
}
// 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 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();
}
}
// map standard API return values (defined WinError.h)
// to WBEMish hresults (defined in WbemCli.h)
HRESULT WinErrorToWBEMhResult(LONG error)
{
HRESULT hr = WBEM_E_FAILED;
switch (error)
{
case ERROR_SUCCESS:
hr = WBEM_S_NO_ERROR;
break;
case ERROR_ACCESS_DENIED:
hr = WBEM_E_ACCESS_DENIED;
break;
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OUTOFMEMORY:
hr = WBEM_E_OUT_OF_MEMORY;
break;
case ERROR_ALREADY_EXISTS:
hr = WBEM_E_ALREADY_EXISTS;
break;
case ERROR_BAD_NETPATH:
case ERROR_INVALID_DATA:
case ERROR_BAD_PATHNAME:
case REGDB_E_INVALIDVALUE:
case ERROR_PATH_NOT_FOUND:
case ERROR_FILE_NOT_FOUND:
case ERROR_INVALID_PRINTER_NAME:
case ERROR_BAD_USERNAME:
case ERROR_NOT_READY:
case ERROR_INVALID_NAME:
hr = WBEM_E_NOT_FOUND;
break;
default:
hr = WBEM_E_FAILED;
}
return hr;
}
// Copied from sid.h
bool GetNameAndDomainFromPSID(
PSID pSid,
CHString& chstrName,
CHString& chstrDomain)
{
bool fRet = false;
// pSid should be valid...
_ASSERT( (pSid != NULL) && ::IsValidSid( pSid ) );
if ( (pSid != NULL) && ::IsValidSid( pSid ) )
{
// Initialize account name and domain name
LPTSTR pszAccountName = NULL;
LPTSTR pszDomainName = NULL;
DWORD dwAccountNameSize = 0;
DWORD dwDomainNameSize = 0;
DWORD dwLastError = ERROR_SUCCESS;
BOOL bResult = TRUE;
try
{
// This call should fail
SID_NAME_USE snuAccountType;
bResult = ::LookupAccountSid( NULL,
pSid,
pszAccountName,
&dwAccountNameSize,
pszDomainName,
&dwDomainNameSize,
&snuAccountType );
dwLastError = ::GetLastError();
if ( ERROR_INSUFFICIENT_BUFFER == dwLastError )
{
// Allocate buffers
if ( dwAccountNameSize != 0 )
{
pszAccountName = (LPTSTR) new TCHAR[ dwAccountNameSize * sizeof(TCHAR) ];
}
if ( dwDomainNameSize != 0 )
{
pszDomainName = (LPTSTR) new TCHAR[ dwDomainNameSize * sizeof(TCHAR) ];
}
// Make second call
bResult = ::LookupAccountSid( NULL,
pSid,
pszAccountName,
&dwAccountNameSize,
pszDomainName,
&dwDomainNameSize,
&snuAccountType );
if ( bResult == TRUE )
{
chstrName = pszAccountName;
chstrDomain = pszDomainName;
}
else
{
// There are some accounts that do not have names, such as Logon Ids,
// for example S-1-5-X-Y. So this is still legal
chstrName = _T("Unknown Account");
chstrDomain = _T("Unknown Domain");
}
if ( NULL != pszAccountName )
{
delete pszAccountName;
pszAccountName = NULL;
}
if ( NULL != pszDomainName )
{
delete pszDomainName;
pszDomainName = NULL;
}
fRet = true;
} // If ERROR_INSUFFICIENT_BUFFER
} // try
catch(...)
{
if ( NULL != pszAccountName )
{
delete pszAccountName;
pszAccountName = NULL;
}
if ( NULL != pszDomainName )
{
delete pszDomainName;
pszDomainName = NULL;
}
throw;
}
} // IF IsValidSid
return fRet;
}