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.
2153 lines
55 KiB
2153 lines
55 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995.
|
|
//
|
|
// File: libmain.cxx
|
|
//
|
|
// Contents: LibMain for nds.dll
|
|
//
|
|
// Functions: LibMain, DllGetClassObject
|
|
//
|
|
// History: 25-Oct-94 KrishnaG Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include "oleds.hxx"
|
|
#pragma hdrstop
|
|
|
|
CRITICAL_SECTION g_StringsCriticalSection;
|
|
WCHAR g_szBuiltin[100];
|
|
WCHAR g_szNT_Authority[100];
|
|
WCHAR g_szAccountOperators[100];
|
|
WCHAR g_szPrintOperators[100];
|
|
WCHAR g_szBackupOperators[100];
|
|
WCHAR g_szServerOperators[100];
|
|
WCHAR g_szPreWindows2000[100];
|
|
|
|
BOOL g_fStringsLoaded = FALSE;
|
|
|
|
//
|
|
// Global variables for dynamically loaded fn's.
|
|
//
|
|
HANDLE g_hDllAdvapi32 = NULL;
|
|
BOOL g_fDllsLoaded = FALSE;
|
|
|
|
extern "C" {
|
|
|
|
HRESULT
|
|
ConvertSidToString(
|
|
PSID pSid,
|
|
LPWSTR String
|
|
);
|
|
}
|
|
|
|
DWORD
|
|
GetDomainDNSNameForDomain(
|
|
LPWSTR pszDomainFlatName,
|
|
BOOL fVerify,
|
|
BOOL fWriteable,
|
|
LPWSTR pszServerName,
|
|
LPWSTR pszDomainDNSName
|
|
);
|
|
|
|
#define GetAce ADSIGetAce
|
|
|
|
#define AddAce ADSIAddAce
|
|
|
|
#define DeleteAce ADSIDeleteAce
|
|
|
|
#define GetAclInformation ADSIGetAclInformation
|
|
|
|
#define SetAclInformation ADSISetAclInformation
|
|
|
|
#define IsValidAcl ADSIIsValidAcl
|
|
|
|
#define InitializeAcl ADSIInitializeAcl
|
|
|
|
#define SetSecurityDescriptorControl ADSISetControlSecurityDescriptor
|
|
|
|
|
|
#define SE_VALID_CONTROL_BITS ( SE_DACL_UNTRUSTED | \
|
|
SE_SERVER_SECURITY | \
|
|
SE_DACL_AUTO_INHERIT_REQ | \
|
|
SE_SACL_AUTO_INHERIT_REQ | \
|
|
SE_DACL_AUTO_INHERITED | \
|
|
SE_SACL_AUTO_INHERITED | \
|
|
SE_DACL_PROTECTED | \
|
|
SE_SACL_PROTECTED )
|
|
|
|
BOOL
|
|
EquivalentServers(
|
|
LPWSTR pszTargetServer,
|
|
LPWSTR pszSourceServer
|
|
);
|
|
|
|
|
|
HRESULT
|
|
SecCreateSidFromArray (
|
|
OUT PSID *PPSid,
|
|
IN PSID_IDENTIFIER_AUTHORITY PSidAuthority,
|
|
IN UCHAR SubAuthorityCount,
|
|
IN ULONG SubAuthorities[],
|
|
OUT PDWORD pdwSidSize
|
|
);
|
|
|
|
HRESULT
|
|
ConvertStringToSid(
|
|
IN PWSTR string,
|
|
OUT PSID *sid,
|
|
OUT PDWORD pdwSidSize
|
|
);
|
|
|
|
HRESULT
|
|
AddFilteredACEs(
|
|
PACL pAcl,
|
|
DWORD dwAclRevision,
|
|
PACE_HEADER *ppAceHdr,
|
|
DWORD dwCountACEs,
|
|
DWORD *pdwAclPosition,
|
|
BOOL fInheritedACEs,
|
|
BOOL fDenyACEs,
|
|
BOOL fDenyObjectACEs,
|
|
BOOL fGrantACEs,
|
|
BOOL fGrantObjectACEs,
|
|
BOOL fAuditACEs
|
|
);
|
|
|
|
//
|
|
// These wrapper functions are needed as some fn's need to
|
|
// be loaded dynamically as they are not available on NT4
|
|
//
|
|
#define SET_SD_CONTROL_API "SetSecurityDescriptorControl"
|
|
|
|
// load library helper
|
|
|
|
HMODULE LoadLibraryHelper(
|
|
LPTSTR pszFileName
|
|
)
|
|
{
|
|
const DWORD iSize = GetSystemDirectory(NULL, 0);
|
|
TCHAR* buffer = NULL;
|
|
DWORD dwTemp = 0;
|
|
HMODULE handle = NULL;
|
|
|
|
if(iSize == 0)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
buffer = new TCHAR[iSize + _tcslen(__TEXT("\\")) + _tcslen(pszFileName)]; // iSize includes the NULL terminiator
|
|
if(!buffer)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
dwTemp = GetSystemDirectory(buffer, iSize);
|
|
if(dwTemp == 0)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
_tcscat(buffer, __TEXT("\\"));
|
|
_tcscat(buffer, pszFileName);
|
|
|
|
handle = LoadLibrary(buffer);
|
|
|
|
error:
|
|
|
|
if(buffer)
|
|
{
|
|
delete [] buffer;
|
|
buffer = NULL;
|
|
}
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Helper that loads functions in advapi32.
|
|
//
|
|
PVOID LoadAdvapi32Function(CHAR *function)
|
|
{
|
|
//
|
|
// Since the strings critical section is only used in this file,
|
|
// be fine just re-using it here.
|
|
//
|
|
if (!g_fDllsLoaded) {
|
|
EnterCriticalSection(&g_StringsCriticalSection);
|
|
if (!g_fDllsLoaded) {
|
|
g_hDllAdvapi32 = LoadLibraryHelper(L"ADVAPI32.DLL");
|
|
//
|
|
// Even if this fails, there is nothing we can do.
|
|
//
|
|
g_fDllsLoaded = TRUE;
|
|
}
|
|
LeaveCriticalSection(&g_StringsCriticalSection);
|
|
}
|
|
|
|
if (g_hDllAdvapi32) {
|
|
return((PVOID*) GetProcAddress((HMODULE) g_hDllAdvapi32, function));
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
typedef DWORD (*PF_SetSecurityDescriptorControl) (
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
|
|
IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet
|
|
);
|
|
|
|
//
|
|
// Wrapper function for the same.
|
|
//
|
|
DWORD SetSecurityDescriptorControlWrapper(
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
|
|
IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet
|
|
)
|
|
{
|
|
static PF_SetSecurityDescriptorControl pfSetSecDescControl = NULL;
|
|
static BOOL f_LoadAttempted = FALSE;
|
|
|
|
//
|
|
// Load the fn and set the variables accordingly.
|
|
//
|
|
if (!f_LoadAttempted && pfSetSecDescControl == NULL) {
|
|
pfSetSecDescControl = (PF_SetSecurityDescriptorControl)
|
|
LoadAdvapi32Function(SET_SD_CONTROL_API);
|
|
f_LoadAttempted = TRUE;
|
|
}
|
|
|
|
if (pfSetSecDescControl != NULL) {
|
|
return ((*pfSetSecDescControl)(
|
|
pSecurityDescriptor,
|
|
ControlBitsOfInterest,
|
|
ControlBitsToSet
|
|
)
|
|
);
|
|
}
|
|
else {
|
|
//
|
|
// This will call the routine in acledit.cxx.
|
|
// We should be in this codepath only in pre win2k
|
|
// machines.
|
|
//
|
|
return SetSecurityDescriptorControl(
|
|
pSecurityDescriptor,
|
|
ControlBitsOfInterest,
|
|
ControlBitsToSet
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
HRESULT
|
|
ConvertSecurityDescriptorToSecDes(
|
|
LPWSTR pszServerName,
|
|
CCredentials& Credentials,
|
|
IADsSecurityDescriptor FAR * pSecDes,
|
|
PSECURITY_DESCRIPTOR * ppSecurityDescriptor,
|
|
PDWORD pdwSDLength,
|
|
BOOL fNTDSType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
SECURITY_DESCRIPTOR AbsoluteSD;
|
|
PSECURITY_DESCRIPTOR pRelative = NULL;
|
|
BOOL Defaulted = FALSE;
|
|
BOOL DaclPresent = FALSE;
|
|
BOOL SaclPresent = FALSE;
|
|
|
|
BOOL fDaclDefaulted = FALSE;
|
|
BOOL fSaclDefaulted = FALSE;
|
|
BOOL fOwnerDefaulted = FALSE;
|
|
BOOL fGroupDefaulted = FALSE;
|
|
|
|
PSID pOwnerSid = NULL;
|
|
PSID pGroupSid = NULL;
|
|
PACL pDacl = NULL;
|
|
PACL pSacl = NULL;
|
|
DWORD dwSDLength = 0;
|
|
BOOL dwStatus = 0;
|
|
|
|
DWORD dwControl = 0;
|
|
DWORD dwRevision = 0;
|
|
|
|
hr = pSecDes->get_Revision((long *)&dwRevision);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = InitializeSecurityDescriptor (
|
|
&AbsoluteSD,
|
|
dwRevision
|
|
);
|
|
if (!dwStatus) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
hr = pSecDes->get_Control((long *)&dwControl);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
dwStatus = SetSecurityDescriptorControlWrapper(
|
|
&AbsoluteSD,
|
|
SE_VALID_CONTROL_BITS,
|
|
(SECURITY_DESCRIPTOR_CONTROL) (dwControl & SE_VALID_CONTROL_BITS)
|
|
);
|
|
if (!dwStatus) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
hr = GetOwnerSecurityIdentifier(
|
|
pszServerName,
|
|
Credentials,
|
|
pSecDes,
|
|
&pOwnerSid,
|
|
&fOwnerDefaulted,
|
|
fNTDSType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = SetSecurityDescriptorOwner(
|
|
&AbsoluteSD,
|
|
pOwnerSid,
|
|
fOwnerDefaulted
|
|
);
|
|
if (!dwStatus) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
hr = GetGroupSecurityIdentifier(
|
|
pszServerName,
|
|
Credentials,
|
|
pSecDes,
|
|
&pGroupSid,
|
|
&fGroupDefaulted,
|
|
fNTDSType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
dwStatus = SetSecurityDescriptorGroup(
|
|
&AbsoluteSD,
|
|
pGroupSid,
|
|
fGroupDefaulted
|
|
);
|
|
|
|
if (!dwStatus) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = GetDacl(
|
|
pszServerName,
|
|
Credentials,
|
|
pSecDes,
|
|
&pDacl,
|
|
&fDaclDefaulted,
|
|
fNTDSType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
if (pDacl || fDaclDefaulted) {
|
|
DaclPresent = TRUE;
|
|
}
|
|
|
|
//
|
|
// This is a special case, basically the DACL is defaulted
|
|
// and pDacl is NULL. In order for this to work correctly,
|
|
// pDacl should be an empty ACL not null.
|
|
//
|
|
if (DaclPresent && !pDacl) {
|
|
pDacl = (PACL) AllocADsMem(sizeof(ACL));
|
|
if (!pDacl) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
dwStatus = InitializeAcl(
|
|
pDacl,
|
|
sizeof(ACL),
|
|
ACL_REVISION // this revision will work for NT4 and Win2k
|
|
);
|
|
if (!dwStatus) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
}
|
|
|
|
dwStatus = SetSecurityDescriptorDacl(
|
|
&AbsoluteSD,
|
|
DaclPresent,
|
|
pDacl,
|
|
fDaclDefaulted
|
|
);
|
|
if (!dwStatus) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
hr = GetSacl(
|
|
pszServerName,
|
|
Credentials,
|
|
pSecDes,
|
|
&pSacl,
|
|
&fSaclDefaulted,
|
|
fNTDSType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
if (pSacl || fSaclDefaulted) {
|
|
SaclPresent = TRUE;
|
|
}
|
|
|
|
dwStatus = SetSecurityDescriptorSacl(
|
|
&AbsoluteSD,
|
|
SaclPresent,
|
|
pSacl,
|
|
fSaclDefaulted
|
|
);
|
|
|
|
if (!dwStatus) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
dwSDLength = GetSecurityDescriptorLength(
|
|
&AbsoluteSD
|
|
);
|
|
|
|
pRelative = AllocADsMem(dwSDLength);
|
|
if (!pRelative) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if (!MakeSelfRelativeSD (&AbsoluteSD, pRelative, &dwSDLength)) {
|
|
FreeADsMem(pRelative);
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
*ppSecurityDescriptor = pRelative;
|
|
*pdwSDLength = dwSDLength;
|
|
|
|
cleanup:
|
|
|
|
if (pDacl) {
|
|
FreeADsMem(pDacl);
|
|
}
|
|
|
|
if (pSacl) {
|
|
FreeADsMem(pSacl);
|
|
}
|
|
|
|
if (pOwnerSid) {
|
|
FreeADsMem(pOwnerSid);
|
|
}
|
|
|
|
if (pGroupSid) {
|
|
FreeADsMem(pGroupSid);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
*ppSecurityDescriptor = NULL;
|
|
*pdwSDLength = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
GetOwnerSecurityIdentifier(
|
|
LPWSTR pszServerName,
|
|
CCredentials& Credentials,
|
|
IADsSecurityDescriptor FAR * pSecDes,
|
|
PSID * ppSid,
|
|
PBOOL pfOwnerDefaulted,
|
|
BOOL fNTDSType
|
|
)
|
|
{
|
|
BSTR bstrOwner = NULL;
|
|
DWORD dwSidSize = 0;
|
|
HRESULT hr = S_OK;
|
|
VARIANT_BOOL varBool = VARIANT_FALSE;
|
|
|
|
hr = pSecDes->get_Owner(
|
|
&bstrOwner
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pSecDes->get_OwnerDefaulted(
|
|
&varBool
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (varBool == VARIANT_FALSE) {
|
|
|
|
if (bstrOwner && *bstrOwner) {
|
|
|
|
hr = ConvertTrusteeToSid(
|
|
pszServerName,
|
|
Credentials,
|
|
bstrOwner,
|
|
ppSid,
|
|
&dwSidSize,
|
|
fNTDSType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
*pfOwnerDefaulted = FALSE;
|
|
}else {
|
|
|
|
*ppSid = NULL;
|
|
*pfOwnerDefaulted = FALSE;
|
|
}
|
|
|
|
}else {
|
|
*ppSid = NULL;
|
|
dwSidSize = 0;
|
|
*pfOwnerDefaulted = TRUE;
|
|
}
|
|
|
|
error:
|
|
|
|
if (bstrOwner) {
|
|
ADsFreeString(bstrOwner);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
GetGroupSecurityIdentifier(
|
|
LPWSTR pszServerName,
|
|
CCredentials& Credentials,
|
|
IADsSecurityDescriptor FAR * pSecDes,
|
|
PSID * ppSid,
|
|
PBOOL pfGroupDefaulted,
|
|
BOOL fNTDSType
|
|
)
|
|
{
|
|
BSTR bstrGroup = NULL;
|
|
DWORD dwSidSize = 0;
|
|
HRESULT hr = S_OK;
|
|
VARIANT_BOOL varBool = VARIANT_FALSE;
|
|
|
|
hr = pSecDes->get_Group(
|
|
&bstrGroup
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pSecDes->get_GroupDefaulted(
|
|
&varBool
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (varBool == VARIANT_FALSE) {
|
|
|
|
if (bstrGroup && *bstrGroup) {
|
|
|
|
hr = ConvertTrusteeToSid(
|
|
pszServerName,
|
|
Credentials,
|
|
bstrGroup,
|
|
ppSid,
|
|
&dwSidSize,
|
|
fNTDSType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
*pfGroupDefaulted = FALSE;
|
|
}else {
|
|
*ppSid = NULL;
|
|
*pfGroupDefaulted = FALSE;
|
|
}
|
|
|
|
}else {
|
|
*ppSid = NULL;
|
|
dwSidSize = 0;
|
|
*pfGroupDefaulted = TRUE;
|
|
}
|
|
|
|
error:
|
|
|
|
if (bstrGroup) {
|
|
ADsFreeString(bstrGroup);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
GetDacl(
|
|
LPWSTR pszServerName,
|
|
CCredentials& Credentials,
|
|
IADsSecurityDescriptor FAR * pSecDes,
|
|
PACL * ppDacl,
|
|
PBOOL pfDaclDefaulted,
|
|
BOOL fNTDSType
|
|
)
|
|
{
|
|
IADsAccessControlList FAR * pDiscAcl = NULL;
|
|
IDispatch FAR * pDispatch = NULL;
|
|
HRESULT hr = S_OK;
|
|
VARIANT_BOOL varBool = VARIANT_FALSE;
|
|
|
|
hr = pSecDes->get_DaclDefaulted(
|
|
&varBool
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (varBool == VARIANT_FALSE) {
|
|
*pfDaclDefaulted = FALSE;
|
|
}else {
|
|
*pfDaclDefaulted = TRUE;
|
|
}
|
|
|
|
hr = pSecDes->get_DiscretionaryAcl(
|
|
&pDispatch
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (!pDispatch) {
|
|
*ppDacl = NULL;
|
|
goto error;
|
|
}
|
|
|
|
hr = pDispatch->QueryInterface(
|
|
IID_IADsAccessControlList,
|
|
(void **)&pDiscAcl
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
hr = ConvertAccessControlListToAcl(
|
|
pszServerName,
|
|
Credentials,
|
|
pDiscAcl,
|
|
ppDacl,
|
|
fNTDSType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pDispatch) {
|
|
pDispatch->Release();
|
|
}
|
|
|
|
if (pDiscAcl) {
|
|
pDiscAcl->Release();
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetSacl(
|
|
LPWSTR pszServerName,
|
|
CCredentials& Credentials,
|
|
IADsSecurityDescriptor FAR * pSecDes,
|
|
PACL * ppSacl,
|
|
PBOOL pfSaclDefaulted,
|
|
BOOL fNTDSType
|
|
)
|
|
{
|
|
IADsAccessControlList FAR * pSystemAcl = NULL;
|
|
IDispatch FAR * pDispatch = NULL;
|
|
HRESULT hr = S_OK;
|
|
VARIANT_BOOL varBool = VARIANT_FALSE;
|
|
|
|
hr = pSecDes->get_SaclDefaulted(
|
|
&varBool
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (varBool == VARIANT_FALSE) {
|
|
*pfSaclDefaulted = FALSE;
|
|
}else {
|
|
*pfSaclDefaulted = TRUE;
|
|
}
|
|
|
|
hr = pSecDes->get_SystemAcl(
|
|
&pDispatch
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (!pDispatch) {
|
|
*ppSacl = NULL;
|
|
goto error;
|
|
}
|
|
|
|
hr = pDispatch->QueryInterface(
|
|
IID_IADsAccessControlList,
|
|
(void **)&pSystemAcl
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
hr = ConvertAccessControlListToAcl(
|
|
pszServerName,
|
|
Credentials,
|
|
pSystemAcl,
|
|
ppSacl,
|
|
fNTDSType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pDispatch) {
|
|
pDispatch->Release();
|
|
}
|
|
|
|
if (pSystemAcl) {
|
|
pSystemAcl->Release();
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
ConvertAccessControlListToAcl(
|
|
LPWSTR pszServerName,
|
|
CCredentials& Credentials,
|
|
IADsAccessControlList FAR * pAccessList,
|
|
PACL * ppAcl,
|
|
BOOL fNTDSType
|
|
)
|
|
{
|
|
IUnknown * pUnknown = NULL;
|
|
IEnumVARIANT * pEnumerator = NULL;
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
DWORD iAclPosition = 0;
|
|
DWORD cReturned = 0;
|
|
VARIANT varAce;
|
|
|
|
DWORD dwAceCount = 0;
|
|
|
|
IADsAccessControlEntry FAR * pAccessControlEntry = NULL;
|
|
|
|
LPBYTE pTempAce = NULL;
|
|
DWORD dwCount = 0;
|
|
|
|
PACL pAcl = NULL;
|
|
DWORD dwAclSize = 0;
|
|
PACE_HEADER * ppAceHdr = NULL;
|
|
|
|
DWORD dwRet = 0;
|
|
DWORD dwAclRevision = 0;
|
|
DWORD dwError = 0;
|
|
|
|
//
|
|
// Defines the canonical ordering of the ACEs.
|
|
//
|
|
struct AceOrderElement
|
|
{
|
|
BOOL fInheritedACEs;
|
|
BOOL fDenyACEs;
|
|
BOOL fDenyObjectACEs;
|
|
BOOL fGrantACEs;
|
|
BOOL fGrantObjectACEs;
|
|
BOOL fAuditACEs;
|
|
} AceOrderSequence [] =
|
|
{
|
|
{FALSE, FALSE, FALSE, FALSE, FALSE, TRUE},
|
|
{FALSE, TRUE, FALSE, FALSE, FALSE, FALSE},
|
|
{FALSE, FALSE, TRUE, FALSE, FALSE, FALSE},
|
|
{FALSE, FALSE, FALSE, TRUE, FALSE, FALSE},
|
|
{FALSE, FALSE, FALSE, FALSE, TRUE, FALSE},
|
|
|
|
{TRUE, FALSE, FALSE, FALSE, FALSE, TRUE},
|
|
{TRUE, TRUE, FALSE, FALSE, FALSE, FALSE},
|
|
{TRUE, FALSE, TRUE, FALSE, FALSE, FALSE},
|
|
{TRUE, FALSE, FALSE, TRUE, FALSE, FALSE},
|
|
{TRUE, FALSE, FALSE, FALSE, TRUE, FALSE}
|
|
};
|
|
|
|
DWORD dwAceOrderSequenceLen = sizeof(AceOrderSequence) / sizeof (AceOrderElement);
|
|
|
|
|
|
hr = pAccessList->get_AceCount((long *)&dwAceCount);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
hr = pAccessList->get__NewEnum(
|
|
&pUnknown
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pUnknown->QueryInterface(
|
|
IID_IEnumVARIANT,
|
|
(void FAR * FAR *)&pEnumerator
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
|
|
ppAceHdr = (PACE_HEADER *)AllocADsMem(sizeof(PACE_HEADER)*dwAceCount);
|
|
if (!ppAceHdr) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
for (i = 0; i < dwAceCount; i++) {
|
|
|
|
VariantInit(&varAce);
|
|
|
|
hr = pEnumerator->Next(
|
|
1,
|
|
&varAce,
|
|
&cReturned
|
|
);
|
|
|
|
//
|
|
// Need to BAIL here as we could not convert an ACL.
|
|
//
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
hr = (V_DISPATCH(&varAce))->QueryInterface(
|
|
IID_IADsAccessControlEntry,
|
|
(void **)&pAccessControlEntry
|
|
);
|
|
|
|
VariantClear(&varAce);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
hr = ConvertAccessControlEntryToAce(
|
|
pszServerName,
|
|
Credentials,
|
|
pAccessControlEntry,
|
|
&(pTempAce),
|
|
fNTDSType
|
|
);
|
|
|
|
if (pAccessControlEntry) {
|
|
pAccessControlEntry->Release();
|
|
pAccessControlEntry = NULL;
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
|
|
*(ppAceHdr + dwCount) = (PACE_HEADER)pTempAce;
|
|
|
|
|
|
|
|
|
|
dwCount++;
|
|
}
|
|
|
|
hr = ComputeTotalAclSize(ppAceHdr, dwCount, &dwAclSize);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pAcl = (PACL)AllocADsMem(dwAclSize);
|
|
if (!pAcl) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = pAccessList->get_AclRevision((long *)&dwAclRevision);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
dwRet = InitializeAcl(
|
|
pAcl,
|
|
dwAclSize,
|
|
dwAclRevision
|
|
);
|
|
if (!dwRet) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// Add the ACEs in canonical ordering:
|
|
// All Explitic Audit
|
|
// All Explicit Deny
|
|
// All Explicit Object Deny
|
|
// All Explicit Allow
|
|
// All Explicit Object Allow
|
|
//
|
|
// All Inherited Audit
|
|
// All Inherited Deny
|
|
// All Inherited Object Deny
|
|
// All Inherited Allow
|
|
// All Inherited Object Allow
|
|
//
|
|
|
|
for (i=0; i < dwAceOrderSequenceLen; i++) {
|
|
|
|
hr = AddFilteredACEs(
|
|
pAcl,
|
|
dwAclRevision,
|
|
ppAceHdr,
|
|
dwCount,
|
|
&iAclPosition,
|
|
AceOrderSequence[i].fInheritedACEs,
|
|
AceOrderSequence[i].fDenyACEs,
|
|
AceOrderSequence[i].fDenyObjectACEs,
|
|
AceOrderSequence[i].fGrantACEs,
|
|
AceOrderSequence[i].fGrantObjectACEs,
|
|
AceOrderSequence[i].fAuditACEs
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
*ppAcl = pAcl;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (ppAceHdr) {
|
|
for (i = 0; i < dwCount; i++) {
|
|
if (*(ppAceHdr + i)) {
|
|
|
|
FreeADsMem(*(ppAceHdr + i));
|
|
}
|
|
}
|
|
|
|
FreeADsMem(ppAceHdr);
|
|
}
|
|
|
|
if (pUnknown) {
|
|
pUnknown->Release();
|
|
}
|
|
|
|
if (pEnumerator) {
|
|
pEnumerator->Release();
|
|
}
|
|
|
|
if(FAILED(hr) && pAcl)
|
|
{
|
|
FreeADsMem(pAcl);
|
|
}
|
|
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
/*
|
|
* AddFilteredACEs
|
|
*
|
|
* Adds ACEs from ppAceHdr (of size dwCountACEs) to the ACL pAcl
|
|
* (of revision dwAclRevision), starting at position *pdwAclPosition in
|
|
* the ACL, based on the filter settings fInheritedACEs, fDenyACEs,
|
|
* fGrantACEs, fDenyObjectACEs, fGrantObjectACEs, and fAuditACEs.
|
|
*
|
|
* On return, *pdwAclPosition is the position to continue adding
|
|
* ACEs at.
|
|
*
|
|
*/
|
|
HRESULT
|
|
AddFilteredACEs(
|
|
PACL pAcl, // the ACL to add the ACEs to
|
|
DWORD dwAclRevision, // the revision of the ACL
|
|
PACE_HEADER *ppAceHdr, // the ACEs to add
|
|
DWORD dwCountACEs, // number of ACEs in ppAceHdr
|
|
DWORD *pdwAclPosition, // starting(in)/ending(out) position
|
|
BOOL fInheritedACEs, // include explicit or inherited ACEs?
|
|
BOOL fDenyACEs, // include access-deny ACEs?
|
|
BOOL fDenyObjectACEs, // include access-deny-object ACEs?
|
|
BOOL fGrantACEs, // include access-grant ACEs?
|
|
BOOL fGrantObjectACEs, // include access-grant-object ACEs?
|
|
BOOL fAuditACEs // include audit ACEs?
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwStatus;
|
|
|
|
DWORD i;
|
|
DWORD iAclPosition = *pdwAclPosition;
|
|
BOOL fAddIt;
|
|
|
|
BOOL fIsAceInherited;
|
|
|
|
for (i = 0; i < dwCountACEs; i++) {
|
|
|
|
//
|
|
// Filter based on whether we're adding explicit or inherited ACEs
|
|
//
|
|
fIsAceInherited = (((*(ppAceHdr + i))->AceFlags) & INHERITED_ACE) ? TRUE : FALSE;
|
|
|
|
if ( fIsAceInherited == fInheritedACEs) {
|
|
|
|
fAddIt = FALSE;
|
|
|
|
//
|
|
// Filter based on ACE type
|
|
//
|
|
switch ((*(ppAceHdr + i))->AceType) {
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
if (fGrantACEs) {
|
|
fAddIt = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
if (fGrantObjectACEs) {
|
|
fAddIt = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
if (fDenyACEs) {
|
|
fAddIt = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
if (fDenyObjectACEs) {
|
|
fAddIt = TRUE;
|
|
}
|
|
break;
|
|
|
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|
if (fAuditACEs) {
|
|
fAddIt = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If the ACE met the criteria, add it to the ACL
|
|
//
|
|
if (fAddIt) {
|
|
dwStatus = AddAce(
|
|
pAcl,
|
|
dwAclRevision,
|
|
iAclPosition++,
|
|
(LPBYTE)*(ppAceHdr + i),
|
|
(*(ppAceHdr + i))->AceSize
|
|
);
|
|
|
|
if (!dwStatus) {
|
|
|
|
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
|
|
*pdwAclPosition = iAclPosition;
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ConvertAccessControlEntryToAce(
|
|
LPWSTR pszServerName,
|
|
CCredentials& Credentials,
|
|
IADsAccessControlEntry * pAccessControlEntry,
|
|
LPBYTE * ppAce,
|
|
BOOL fNTDSType
|
|
)
|
|
{
|
|
|
|
DWORD dwAceType = 0;
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrTrustee = NULL;
|
|
PSID pSid = NULL;
|
|
DWORD dwSidSize = 0;
|
|
|
|
DWORD dwAceFlags = 0;
|
|
DWORD dwAccessMask = 0;
|
|
DWORD dwAceSize = 0;
|
|
LPBYTE pAce = NULL;
|
|
PACCESS_MASK pAccessMask = NULL;
|
|
PSID pSidAddress = NULL;
|
|
|
|
PUSHORT pCompoundAceType = NULL;
|
|
DWORD dwCompoundAceType = 0;
|
|
|
|
PACE_HEADER pAceHeader = NULL;
|
|
|
|
LPBYTE pOffset = NULL;
|
|
|
|
BSTR bstrObjectTypeClsid = NULL;
|
|
BSTR bstrInheritedObjectTypeClsid = NULL;
|
|
|
|
GUID ObjectTypeGUID;
|
|
GUID InheritedObjectTypeGUID;
|
|
PULONG pFlags;
|
|
DWORD dwFlags = 0;
|
|
BOOL fLookupTrustee = TRUE;
|
|
BOOL fSidValid = FALSE;
|
|
IADsAcePrivate *pPrivAce = NULL;
|
|
|
|
hr = pAccessControlEntry->get_AceType((LONG *)&dwAceType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pAccessControlEntry->get_Trustee(&bstrTrustee);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// We need to see if we can use a cached SID here.
|
|
//
|
|
hr = pAccessControlEntry->QueryInterface(
|
|
IID_IADsAcePrivate,
|
|
(void **)&pPrivAce
|
|
);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
//
|
|
// See if the SID is valid and if so try and retrieve it.
|
|
//
|
|
hr = pPrivAce->isSidValid(&fSidValid);
|
|
if (SUCCEEDED(hr) && fSidValid) {
|
|
|
|
hr = pPrivAce->getSid(
|
|
&pSid,
|
|
&dwSidSize
|
|
);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
fLookupTrustee = FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (fLookupTrustee) {
|
|
|
|
hr = ConvertTrusteeToSid(
|
|
pszServerName,
|
|
Credentials,
|
|
bstrTrustee,
|
|
&pSid,
|
|
&dwSidSize,
|
|
fNTDSType
|
|
);
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pAccessControlEntry->get_AceFlags((long *)&dwAceFlags);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pAccessControlEntry->get_AccessMask((long *)&dwAccessMask);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// we will compensateby adding the entire ACE size
|
|
//
|
|
|
|
dwAceSize = dwSidSize - sizeof(ULONG);
|
|
|
|
switch (dwAceType) {
|
|
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
dwAceSize += sizeof(ACCESS_ALLOWED_ACE);
|
|
pAce = (LPBYTE)AllocADsMem(dwAceSize);
|
|
if (!pAce) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
pAceHeader = (PACE_HEADER)pAce;
|
|
pAceHeader->AceType = (UCHAR)dwAceType;
|
|
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
|
|
pAceHeader->AceSize = (USHORT)dwAceSize;
|
|
|
|
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
|
|
|
|
*pAccessMask = (ACCESS_MASK)dwAccessMask;
|
|
|
|
pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK));
|
|
memcpy(pSidAddress, pSid, dwSidSize);
|
|
break;
|
|
|
|
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
dwAceSize += sizeof(ACCESS_ALLOWED_ACE);
|
|
pAce = (LPBYTE)AllocADsMem(dwAceSize);
|
|
if (!pAce) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
pAceHeader = (PACE_HEADER)pAce;
|
|
pAceHeader->AceType = (UCHAR)dwAceType;
|
|
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
|
|
pAceHeader->AceSize = (USHORT)dwAceSize;
|
|
|
|
|
|
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
|
|
|
|
*pAccessMask = (ACCESS_MASK)dwAccessMask;
|
|
|
|
|
|
pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK));
|
|
memcpy(pSidAddress, pSid, dwSidSize);
|
|
break;
|
|
|
|
|
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|
dwAceSize += sizeof(ACCESS_ALLOWED_ACE);
|
|
pAce = (LPBYTE)AllocADsMem(dwAceSize);
|
|
if (!pAce) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
pAceHeader = (PACE_HEADER)pAce;
|
|
pAceHeader->AceType = (UCHAR)dwAceType;
|
|
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
|
|
pAceHeader->AceSize = (USHORT)dwAceSize;
|
|
|
|
|
|
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
|
|
|
|
*pAccessMask = (ACCESS_MASK)dwAccessMask;
|
|
|
|
|
|
pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK));
|
|
memcpy(pSidAddress, pSid, dwSidSize);
|
|
break;
|
|
|
|
case SYSTEM_ALARM_ACE_TYPE:
|
|
dwAceSize += sizeof(ACCESS_ALLOWED_ACE);
|
|
pAce = (LPBYTE)AllocADsMem(dwAceSize);
|
|
if (!pAce) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
pAceHeader = (PACE_HEADER)pAce;
|
|
pAceHeader->AceType = (UCHAR)dwAceType;
|
|
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
|
|
pAceHeader->AceSize = (USHORT)dwAceSize;
|
|
|
|
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
|
|
|
|
*pAccessMask = (ACCESS_MASK)dwAccessMask;
|
|
|
|
pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK));
|
|
memcpy(pSidAddress, pSid, dwSidSize);
|
|
break;
|
|
|
|
|
|
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
|
|
dwAceSize += sizeof(COMPOUND_ACCESS_ALLOWED_ACE);
|
|
pAce = (LPBYTE)AllocADsMem(dwAceSize);
|
|
if (!pAce) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
pAceHeader = (PACE_HEADER)pAce;
|
|
pAceHeader->AceType = (UCHAR)dwAceType;
|
|
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
|
|
pAceHeader->AceSize = (USHORT)dwAceSize;
|
|
|
|
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
|
|
|
|
*pAccessMask = (ACCESS_MASK)dwAccessMask;
|
|
|
|
pCompoundAceType = (PUSHORT)(pAccessMask + sizeof(ACCESS_MASK));
|
|
*pCompoundAceType = (USHORT)dwCompoundAceType;
|
|
|
|
//
|
|
// Fill in the reserved field here.
|
|
//
|
|
|
|
pSidAddress = (PSID)((LPBYTE)pCompoundAceType + sizeof(DWORD));
|
|
memcpy(pSidAddress, pSid, dwSidSize);
|
|
break;
|
|
|
|
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
|
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|
|
|
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
|
|
|
|
|
|
hr = pAccessControlEntry->get_AceFlags((LONG *)&dwAceFlags);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pAccessControlEntry->get_Flags((LONG *)&dwFlags);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (dwFlags & ACE_OBJECT_TYPE_PRESENT) {
|
|
dwAceSize += sizeof(GUID);
|
|
}
|
|
|
|
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
|
|
dwAceSize += sizeof(GUID);
|
|
}
|
|
|
|
hr = pAccessControlEntry->get_ObjectType(&bstrObjectTypeClsid);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = CLSIDFromString(bstrObjectTypeClsid, &ObjectTypeGUID);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pAccessControlEntry->get_InheritedObjectType(&bstrInheritedObjectTypeClsid);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = CLSIDFromString(bstrInheritedObjectTypeClsid, &InheritedObjectTypeGUID);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
|
|
dwAceSize += sizeof(ACCESS_ALLOWED_OBJECT_ACE);
|
|
pAce = (LPBYTE)AllocADsMem(dwAceSize);
|
|
if (!pAce) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
pAceHeader = (PACE_HEADER)pAce;
|
|
pAceHeader->AceType = (UCHAR)dwAceType;
|
|
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
|
|
pAceHeader->AceSize = (USHORT)dwAceSize;
|
|
|
|
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
|
|
|
|
*pAccessMask = (ACCESS_MASK)dwAccessMask;
|
|
|
|
//
|
|
// Fill in Flags
|
|
//
|
|
|
|
pOffset = (LPBYTE)((LPBYTE)pAceHeader + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
|
|
|
|
pFlags = (PULONG)(pOffset);
|
|
|
|
*pFlags = dwFlags;
|
|
|
|
pOffset += sizeof(ULONG);
|
|
|
|
if (dwFlags & ACE_OBJECT_TYPE_PRESENT) {
|
|
|
|
memcpy(pOffset, &ObjectTypeGUID, sizeof(GUID));
|
|
|
|
pOffset += sizeof(GUID);
|
|
|
|
}
|
|
|
|
|
|
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
|
|
|
|
memcpy(pOffset, &InheritedObjectTypeGUID, sizeof(GUID));
|
|
|
|
pOffset += sizeof(GUID);
|
|
}
|
|
|
|
pSidAddress = (PSID)((LPBYTE)pOffset);
|
|
memcpy(pSidAddress, pSid, dwSidSize);
|
|
break;
|
|
|
|
default:
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_ACL);
|
|
BAIL_ON_FAILURE(hr);
|
|
break;
|
|
|
|
}
|
|
|
|
*ppAce = pAce;
|
|
|
|
error:
|
|
|
|
if (bstrTrustee) {
|
|
ADsFreeString(bstrTrustee);
|
|
}
|
|
|
|
if (pSid) {
|
|
FreeADsMem(pSid);
|
|
}
|
|
|
|
if (bstrObjectTypeClsid) {
|
|
SysFreeString(bstrObjectTypeClsid);
|
|
}
|
|
|
|
if (bstrInheritedObjectTypeClsid) {
|
|
SysFreeString(bstrInheritedObjectTypeClsid);
|
|
}
|
|
|
|
if (pPrivAce) {
|
|
pPrivAce->Release();
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
ComputeTotalAclSize(
|
|
PACE_HEADER * ppAceHdr,
|
|
DWORD dwAceCount,
|
|
PDWORD pdwAclSize
|
|
)
|
|
{
|
|
DWORD i = 0;
|
|
PACE_HEADER pAceHdr = NULL;
|
|
DWORD dwAceSize = 0;
|
|
DWORD dwAclSize = 0;
|
|
|
|
for (i = 0; i < dwAceCount; i++) {
|
|
|
|
pAceHdr = *(ppAceHdr + i);
|
|
dwAceSize = pAceHdr->AceSize;
|
|
dwAclSize += dwAceSize;
|
|
}
|
|
|
|
dwAclSize += sizeof(ACL);
|
|
|
|
*pdwAclSize = dwAclSize;
|
|
|
|
RRETURN(S_OK);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
ParseAccountName(LPWSTR szFullAccountName,
|
|
LPWSTR *pszUserDomainName,
|
|
LPWSTR *pszUserAccountName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwDomain = 0;
|
|
BOOLEAN bFound = FALSE;
|
|
LPWSTR szUserDomainName = NULL;
|
|
LPWSTR szUserAccountName = NULL;
|
|
LPWSTR szCount = szFullAccountName;
|
|
|
|
if (!szFullAccountName) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
while (*szCount) {
|
|
if (*szCount == '\\') {
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
dwDomain++;
|
|
szCount++;
|
|
}
|
|
|
|
if (bFound) {
|
|
DWORD dwRest = 0;
|
|
szUserDomainName = (LPWSTR)AllocADsMem(sizeof(WCHAR) * (dwDomain+1));
|
|
if (!szUserDomainName) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
wcsncpy(szUserDomainName,
|
|
szFullAccountName,
|
|
dwDomain);
|
|
szUserDomainName[dwDomain] = L'\0';
|
|
|
|
szUserAccountName = AllocADsStr(szCount+1);
|
|
if (!szUserAccountName) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
}
|
|
else {
|
|
szUserAccountName = AllocADsStr(szFullAccountName);
|
|
if (!szUserAccountName) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
szUserDomainName = NULL;
|
|
}
|
|
*pszUserAccountName = szUserAccountName;
|
|
*pszUserDomainName = szUserDomainName;
|
|
return hr;
|
|
|
|
error:
|
|
if (szUserAccountName) {
|
|
FreeADsMem(szUserAccountName);
|
|
}
|
|
if (szUserDomainName) {
|
|
FreeADsMem(szUserDomainName);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ConvertTrusteeToSid(
|
|
LPWSTR pszServerName,
|
|
CCredentials& Credentials,
|
|
BSTR bstrTrustee,
|
|
PSID * ppSid,
|
|
PDWORD pdwSidSize,
|
|
BOOL fNTDSType
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BYTE Sid[MAX_PATH];
|
|
DWORD dwSidSize = sizeof(Sid);
|
|
DWORD dwRet = 0;
|
|
DWORD dwErr = 0;
|
|
WCHAR szDomainName[MAX_PATH];
|
|
DWORD dwDomainSize = sizeof(szDomainName)/sizeof(WCHAR);
|
|
SID_NAME_USE eUse;
|
|
|
|
PSID pSid = NULL;
|
|
|
|
LPWSTR szUserDomainName = NULL;
|
|
LPWSTR szUserAccountName = NULL;
|
|
LPWSTR szAccountName = NULL;
|
|
BOOL fForceVerify = FALSE;
|
|
|
|
//
|
|
// Load the strings into table if necessary
|
|
//
|
|
if (!g_fStringsLoaded) {
|
|
|
|
EnterCriticalSection(&g_StringsCriticalSection);
|
|
|
|
//
|
|
// Verify flag again.
|
|
//
|
|
if (!g_fStringsLoaded) {
|
|
|
|
dwRet = LoadStringW(
|
|
g_hInst,
|
|
ADS_BUILTIN,
|
|
g_szBuiltin,
|
|
sizeof( g_szBuiltin ) / sizeof( WCHAR )
|
|
);
|
|
|
|
if (!dwRet) {
|
|
//
|
|
// Default to English values.
|
|
//
|
|
wcscpy(g_szBuiltin, L"BUILTIN");
|
|
}
|
|
|
|
dwRet = LoadStringW(
|
|
g_hInst,
|
|
ADS_NT_AUTHORITY,
|
|
g_szNT_Authority,
|
|
sizeof( g_szNT_Authority ) / sizeof( WCHAR )
|
|
);
|
|
|
|
if (!dwRet) {
|
|
//
|
|
// Default to English values.
|
|
//
|
|
wcscpy(g_szNT_Authority, L"NT AUTHORITY");
|
|
}
|
|
|
|
dwRet = LoadStringW(
|
|
g_hInst,
|
|
ADS_ACCOUNT_OPERATORS,
|
|
g_szAccountOperators,
|
|
sizeof( g_szAccountOperators ) / sizeof( WCHAR )
|
|
);
|
|
|
|
if (!dwRet) {
|
|
//
|
|
// Default to English values.
|
|
//
|
|
wcscpy(g_szAccountOperators, L"Account Operators");
|
|
}
|
|
|
|
dwRet = LoadStringW(
|
|
g_hInst,
|
|
ADS_PRINT_OPERATORS,
|
|
g_szPrintOperators,
|
|
sizeof( g_szPrintOperators ) / sizeof( WCHAR )
|
|
);
|
|
|
|
if (!dwRet) {
|
|
//
|
|
// Default to English values.
|
|
//
|
|
wcscpy(g_szPrintOperators, L"Print Operators");
|
|
}
|
|
|
|
dwRet = LoadStringW(
|
|
g_hInst,
|
|
ADS_BACKUP_OPERATORS,
|
|
g_szBackupOperators,
|
|
sizeof( g_szBackupOperators ) / sizeof( WCHAR )
|
|
);
|
|
|
|
if (!dwRet) {
|
|
//
|
|
// Default to English values.
|
|
//
|
|
wcscpy(g_szBackupOperators, L"Backup Operators");
|
|
}
|
|
|
|
dwRet = LoadStringW(
|
|
g_hInst,
|
|
ADS_SERVER_OPERATORS,
|
|
g_szServerOperators,
|
|
sizeof( g_szServerOperators ) / sizeof( WCHAR )
|
|
);
|
|
|
|
if (!dwRet) {
|
|
//
|
|
// Default to English values.
|
|
//
|
|
wcscpy(g_szServerOperators, L"Server Operators");
|
|
}
|
|
|
|
dwRet = LoadStringW(
|
|
g_hInst,
|
|
ADS_PRE_WIN2000,
|
|
g_szPreWindows2000,
|
|
sizeof( g_szPreWindows2000 ) / sizeof( WCHAR )
|
|
);
|
|
|
|
if (!dwRet) {
|
|
//
|
|
// Default to English values.
|
|
//
|
|
wcscpy(
|
|
g_szPreWindows2000,
|
|
L"Pre-Windows 2000 Compatible Access"
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
g_fStringsLoaded = TRUE;
|
|
|
|
LeaveCriticalSection(&g_StringsCriticalSection);
|
|
|
|
}
|
|
|
|
//
|
|
//
|
|
// parse Trustee and determine whether its NTDS or U2
|
|
//
|
|
|
|
if (fNTDSType) {
|
|
WCHAR szDomainName[MAX_PATH];
|
|
WCHAR szServerName[MAX_PATH];
|
|
LPWSTR szLookupServer = NULL;
|
|
BOOL fSpecialLookup = FALSE;
|
|
BOOL fLookupOnServer = FALSE;
|
|
DWORD dwTmpSidLen = 0;
|
|
|
|
dwSidSize = sizeof(Sid);
|
|
szAccountName = bstrTrustee;
|
|
|
|
hr = ParseAccountName(bstrTrustee,
|
|
&szUserDomainName,
|
|
&szUserAccountName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Need to look these up on the server only.
|
|
//
|
|
if (szUserAccountName
|
|
&& ((_wcsicmp(szUserAccountName, g_szAccountOperators) == 0)
|
|
|| (_wcsicmp(szUserAccountName, g_szPrintOperators) == 0)
|
|
|| (_wcsicmp(szUserAccountName, g_szBackupOperators) == 0)
|
|
|| (_wcsicmp(szUserAccountName, g_szServerOperators) == 0)
|
|
|| (_wcsicmp(szUserAccountName, g_szPreWindows2000) == 0)
|
|
)
|
|
) {
|
|
if (szUserDomainName
|
|
&& (_wcsicmp(szUserDomainName, g_szBuiltin)) == 0) {
|
|
fSpecialLookup = TRUE;
|
|
} else {
|
|
fSpecialLookup = FALSE;
|
|
}
|
|
} // special users
|
|
|
|
if (fSpecialLookup ||
|
|
(szUserDomainName &&
|
|
(_wcsicmp(szUserDomainName, g_szBuiltin) != 0) &&
|
|
(_wcsicmp(szUserDomainName, g_szNT_Authority) != 0))
|
|
) {
|
|
|
|
//
|
|
// We will come back here and do a force retry
|
|
// if the server is down.
|
|
//
|
|
retryForce:
|
|
//
|
|
// Force hr to S_OK. This will be needed especially
|
|
// when we jump to the retryForce label.
|
|
//
|
|
hr = S_OK;
|
|
|
|
//
|
|
// Set Lookup on server to true so that later
|
|
// on we do not do the lookup on the server again.
|
|
// In some cases just like we fall back to local machine,
|
|
// we need to look at the server if the local machine fails.
|
|
// this will be the case for mixed locale domains.
|
|
//
|
|
DWORD dwStatus = GetDomainDNSNameForDomain(
|
|
fSpecialLookup ?
|
|
NULL :
|
|
szUserDomainName,
|
|
fForceVerify, // forceVerify
|
|
FALSE,
|
|
szServerName,
|
|
szDomainName
|
|
);
|
|
|
|
fLookupOnServer = TRUE;
|
|
|
|
if (dwStatus) {
|
|
szLookupServer = NULL;
|
|
}
|
|
else {
|
|
szLookupServer = szServerName;
|
|
}
|
|
szAccountName = szUserAccountName;
|
|
}
|
|
|
|
dwRet = LookupAccountName(
|
|
szLookupServer,
|
|
bstrTrustee,
|
|
Sid,
|
|
&dwSidSize,
|
|
szDomainName,
|
|
&dwDomainSize,
|
|
(PSID_NAME_USE)&eUse
|
|
);
|
|
if (!dwRet) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
else {
|
|
//
|
|
// Update the length of the SID.
|
|
//
|
|
|
|
//
|
|
// Call needed on NT4 where GetLenghtSid does not
|
|
// reset the error correctly leading to false errors.
|
|
//
|
|
SetLastError(NO_ERROR);
|
|
|
|
dwTmpSidLen = GetLengthSid(Sid);
|
|
|
|
if ((dwRet = GetLastError()) == NO_ERROR) {
|
|
//
|
|
// Got the correct length so update dwSidSize
|
|
//
|
|
dwSidSize = dwTmpSidLen;
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr)
|
|
&& hr != HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)) {
|
|
|
|
//
|
|
// This code path should not be hit often but it can
|
|
// happen on multi locale domains. The server when might
|
|
// have returned say Builtin instead of german for the same.
|
|
// If the client is german we will be looking for germanbuiltin
|
|
// and that wont work. The lookup will fail locally but
|
|
// will succeed on the server. This is especially true for
|
|
// Builtin\Print Operators as that can only be resolved on the DC.
|
|
//
|
|
if (pszServerName) {
|
|
//
|
|
// Before we do a dsgetdc, we should try with
|
|
// the serverName passed in.
|
|
//
|
|
hr = S_OK;
|
|
dwRet = LookupAccountName(
|
|
pszServerName,
|
|
bstrTrustee,
|
|
Sid,
|
|
&dwSidSize,
|
|
szDomainName,
|
|
&dwDomainSize,
|
|
(PSID_NAME_USE)&eUse
|
|
);
|
|
if (!dwRet) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
//
|
|
// force server name to NULL so we wont
|
|
// try this again.
|
|
//
|
|
pszServerName = NULL;
|
|
}
|
|
else {
|
|
//
|
|
// Update the length of the SID.
|
|
//
|
|
|
|
//
|
|
// Call needed on NT4 where GetLenghtSid does not
|
|
// reset the error correctly leading to false errors.
|
|
//
|
|
SetLastError(NO_ERROR);
|
|
|
|
dwTmpSidLen = GetLengthSid(Sid);
|
|
|
|
if ((dwRet = GetLastError()) == NO_ERROR) {
|
|
//
|
|
// Got the correct length so update dwSidSize
|
|
//
|
|
dwSidSize = dwTmpSidLen;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
//
|
|
// We could be here if either pszServerName was always
|
|
// NULL or if the call to the server failed.
|
|
// The only thing we can do is to retry if we know
|
|
// that the szLookupServer was NULL (that is local machine)
|
|
// or if szLookupServer was something other than the default
|
|
// server for the machine (that is we called DsGetDC with
|
|
// the name of a domain rather than NULL).
|
|
// In all other cases we should not retry and just return
|
|
// the error.
|
|
//
|
|
|
|
|
|
if (fSpecialLookup) {
|
|
//
|
|
// We should not retry in this case as we will not
|
|
// get anything useful. Setting fLookupOnServer
|
|
// to true will force this (if you look above this
|
|
// is not really needed but it helps clear things)
|
|
//
|
|
fLookupOnServer = TRUE;
|
|
}
|
|
else {
|
|
//
|
|
// This was not a special lookup, so we
|
|
// need to retry irrespective of what
|
|
// szLookupServer was.
|
|
//
|
|
fLookupOnServer = FALSE;
|
|
szLookupServer = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// This will do the correct thing even if the above
|
|
// LookUpCall failed. If not we should go down this
|
|
// as we can get stuck in an infinite loop.
|
|
//
|
|
if (FAILED(hr)
|
|
&& !pszServerName
|
|
&& !szLookupServer
|
|
&& !fLookupOnServer
|
|
) {
|
|
//
|
|
// In this case we want to try and call
|
|
// DsGetDCName and hopefully we will get the right
|
|
// DC. fSpecialLookup will be true so that we go to
|
|
// the default DC for the machine/user.
|
|
//
|
|
fSpecialLookup = TRUE;
|
|
goto retryForce;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If failure was due to an expected error then retry
|
|
//
|
|
if (FAILED(hr)
|
|
&& hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)
|
|
) {
|
|
if (!fForceVerify) {
|
|
fForceVerify = TRUE;
|
|
goto retryForce;
|
|
}
|
|
}
|
|
|
|
}else {
|
|
|
|
//
|
|
// We know that LookupAccountName failed,
|
|
// so now try the U2 DS
|
|
//
|
|
dwSidSize = 0;
|
|
|
|
hr = ConvertU2TrusteeToSid(
|
|
pszServerName,
|
|
Credentials,
|
|
bstrTrustee,
|
|
Sid,
|
|
&dwSidSize
|
|
);
|
|
}
|
|
|
|
//
|
|
// If neither the NTDS nor the U2 conversion
|
|
// worked, then try a textual translation
|
|
//
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
hr = ConvertStringToSid(
|
|
bstrTrustee,
|
|
&pSid,
|
|
&dwSidSize
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
memcpy(Sid,pSid, dwSidSize);
|
|
|
|
if (pSid) {
|
|
LocalFree(pSid);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// On NT4 for some reason GetLengthSID does not set lasterror to 0
|
|
//
|
|
SetLastError(NO_ERROR);
|
|
|
|
dwSidSize = GetLengthSid((PSID) Sid);
|
|
|
|
dwErr = GetLastError();
|
|
|
|
//
|
|
// This is an extra check to make sure that we have the
|
|
// correct length.
|
|
//
|
|
if (dwErr != NO_ERROR) {
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr); ;
|
|
|
|
pSid = AllocADsMem(dwSidSize);
|
|
if (!pSid) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
memcpy(pSid, Sid, dwSidSize);
|
|
|
|
*pdwSidSize = dwSidSize;
|
|
|
|
*ppSid = pSid;
|
|
|
|
error:
|
|
|
|
if (szUserDomainName) {
|
|
FreeADsStr(szUserDomainName);
|
|
};
|
|
if (szUserAccountName) {
|
|
FreeADsStr(szUserAccountName);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
/*
|
|
+--------------------------------------------------------------------------------+
|
|
|
|
NAME: get_sid_out_of_string
|
|
|
|
FUNCTION: Convert a string representation of a SID back into
|
|
a sid. The expected format of the string is:
|
|
L"S-1-5-32-549"
|
|
|
|
If a string in a different format or an incorrect or
|
|
incomplete string is given, the operation is failed.
|
|
|
|
The returned sid must be free via a call to SEC_FREE.
|
|
|
|
Arguments:
|
|
|
|
string - The wide string to be converted
|
|
|
|
sid - Where the created SID is to be returned
|
|
|
|
end - Where in the string we stopped processing
|
|
|
|
RETURN:
|
|
|
|
NTSTATUS error codes or success.
|
|
|
|
+--------------------------------------------------------------------------------+
|
|
*/
|
|
HRESULT
|
|
ConvertStringToSid(
|
|
IN PWSTR string,
|
|
OUT PSID *sid,
|
|
OUT PDWORD pdwSidSize
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fResult = FALSE;
|
|
|
|
fResult = ConvertStringSidToSid(string, sid);
|
|
if(fResult)
|
|
{
|
|
fResult = IsValidSid(*sid);
|
|
if(fResult)
|
|
{
|
|
*pdwSidSize = GetLengthSid(*sid);
|
|
}
|
|
else
|
|
{
|
|
if(*sid)
|
|
{
|
|
LocalFree(*sid);
|
|
*sid = NULL;
|
|
}
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SecCreateSidFromArray (
|
|
OUT PSID *PPSid,
|
|
IN PSID_IDENTIFIER_AUTHORITY PSidAuthority,
|
|
IN UCHAR SubAuthorityCount,
|
|
IN ULONG SubAuthorities[],
|
|
OUT PDWORD pdwSidSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a SID with desired authority and sub authorities.
|
|
|
|
NOTE: This routine allocates memory for the SID. When finished
|
|
the caller should free memory using SEC_FREE (PSid).
|
|
|
|
Arguments:
|
|
|
|
PPSid -- addr of ptr to SID to be created
|
|
Note: if SID creation fails ptr set to NULL
|
|
|
|
PSidAuthority -- desired value for SID authority
|
|
|
|
SubAuthorityCount -- number of sub authorities desired
|
|
|
|
SubAuthorities -- sub-authority values, MUST SPECIFY contain
|
|
at least SubAuthorityCount number of values
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if SID created.
|
|
STATUS_UNSUCCESSFUL otherwise.
|
|
|
|
--*/
|
|
{
|
|
USHORT iSub; /* sub-authority index */
|
|
DWORD dwSidSize = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
/* allocate memory for SID */
|
|
|
|
dwSidSize = RtlLengthRequiredSid(SubAuthorityCount);
|
|
*PPSid = (PSID) AllocADsMem( dwSidSize );
|
|
if (! *PPSid){
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
*pdwSidSize = dwSidSize;
|
|
|
|
|
|
/* initialize SID with top level SID identifier authority */
|
|
RtlInitializeSid( *PPSid, PSidAuthority, SubAuthorityCount);
|
|
|
|
/* fill in sub authorities */
|
|
for (iSub=0; iSub < SubAuthorityCount; iSub++)
|
|
* RtlSubAuthoritySid( *PPSid, iSub) = SubAuthorities[iSub];
|
|
|
|
/* sanity check */
|
|
|
|
if ( ! RtlValidSid( *PPSid) ) {
|
|
FreeADsMem( *PPSid);
|
|
*PPSid = NULL;
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
EquivalentServers(
|
|
LPWSTR pszTargetServer,
|
|
LPWSTR pszSourceServer
|
|
)
|
|
{
|
|
if (!pszTargetServer && !pszSourceServer) {
|
|
return(TRUE);
|
|
}
|
|
|
|
if (pszTargetServer && pszSourceServer) {
|
|
|
|
#ifdef WIN95
|
|
if (!_wcsicmp(pszTargetServer, pszSourceServer)) {
|
|
#else
|
|
if (CompareStringW(
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
NORM_IGNORECASE,
|
|
pszTargetServer,
|
|
-1,
|
|
pszSourceServer,
|
|
-1
|
|
) == CSTR_EQUAL ) {
|
|
#endif
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|