mirror of https://github.com/tongzx/nt5src
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.
2727 lines
57 KiB
2727 lines
57 KiB
#include "winnt.hxx"
|
|
#pragma hdrstop
|
|
|
|
HRESULT
|
|
ConvertSafeArrayToVariantArray(
|
|
VARIANT varSafeArray,
|
|
PVARIANT * ppVarArray,
|
|
PDWORD pdwNumVariants
|
|
);
|
|
|
|
|
|
HRESULT
|
|
ConvertByRefSafeArrayToVariantArray(
|
|
VARIANT varSafeArray,
|
|
PVARIANT * ppVarArray,
|
|
PDWORD pdwNumVariants
|
|
);
|
|
|
|
HRESULT
|
|
CreatePropEntry(
|
|
LPWSTR szPropName,
|
|
ADSTYPE dwADsType,
|
|
VARIANT varData,
|
|
REFIID riid,
|
|
LPVOID * ppDispatch
|
|
);
|
|
|
|
|
|
FILTERS Filters[] = {
|
|
{L"user", WINNT_USER_ID},
|
|
{L"group", WINNT_GROUP_ID}, // for backward compatibility
|
|
{L"localgroup", WINNT_LOCALGROUP_ID},
|
|
{L"globalgroup", WINNT_GLOBALGROUP_ID},
|
|
{L"printqueue", WINNT_PRINTER_ID},
|
|
{L"domain", WINNT_DOMAIN_ID},
|
|
{L"computer", WINNT_COMPUTER_ID},
|
|
{L"service", WINNT_SERVICE_ID},
|
|
{L"fileshare", WINNT_FILESHARE_ID},
|
|
{L"schema", WINNT_SCHEMA_ID},
|
|
{L"class", WINNT_CLASS_ID},
|
|
{L"syntax", WINNT_SYNTAX_ID},
|
|
{L"property", WINNT_PROPERTY_ID},
|
|
{L"FPNWfileshare", WINNT_FPNW_FILESHARE_ID}
|
|
};
|
|
|
|
#define MAX_FILTERS (sizeof(Filters)/sizeof(FILTERS))
|
|
|
|
PFILTERS gpFilters = Filters;
|
|
DWORD gdwMaxFilters = MAX_FILTERS;
|
|
extern WCHAR * szProviderName;
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Class: Common
|
|
//
|
|
// Purpose: Contains Winnt routines and properties that are common to
|
|
// all Winnt objects. Winnt objects get the routines and
|
|
// properties through C++ inheritance.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
HRESULT
|
|
BuildADsPath(
|
|
LPWSTR Parent,
|
|
LPWSTR Name,
|
|
LPWSTR *pADsPath
|
|
)
|
|
{
|
|
WCHAR ADsPath[MAX_PATH];
|
|
WCHAR ProviderName[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pszDisplayName = NULL;
|
|
|
|
//
|
|
// We will assert if bad parameters are passed to us.
|
|
// This is because this should never be the case. This
|
|
// is an internal call
|
|
//
|
|
|
|
ADsAssert(Parent && Name);
|
|
ADsAssert(pADsPath);
|
|
|
|
|
|
if ( (wcslen(Parent) + wcslen(Name)) > MAX_PATH - 1) {
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
hr = GetDisplayName(
|
|
Name,
|
|
&pszDisplayName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (!pszDisplayName || !*pszDisplayName) {
|
|
//
|
|
// The display name has to be valid.
|
|
//
|
|
BAIL_ON_FAILURE(hr = E_FAIL);
|
|
}
|
|
|
|
//
|
|
// Special case the Namespace object; if
|
|
// the parent is L"ADs:", then Name = ADsPath
|
|
//
|
|
|
|
if (!_wcsicmp(Parent, L"ADs:")) {
|
|
*pADsPath = AllocADsStr(pszDisplayName);
|
|
if (*pADsPath == NULL) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
else {
|
|
hr = S_OK;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The rest of the cases we expect valid data,
|
|
// Path, Parent and Name are read-only, the end-user
|
|
// cannot modify this data
|
|
//
|
|
|
|
//
|
|
// For the first object, the domain object we do not add
|
|
// the first backslash; so we examine that the parent is
|
|
// L"WinNT:" and skip the slash otherwise we start with
|
|
// the slash
|
|
//
|
|
|
|
wsprintf(ProviderName, L"%s:", szProviderName);
|
|
|
|
wcscpy(ADsPath, Parent);
|
|
|
|
if (_wcsicmp(ADsPath, ProviderName)) {
|
|
wcscat(ADsPath, L"/");
|
|
}else {
|
|
wcscat(ADsPath, L"//");
|
|
}
|
|
wcscat(ADsPath, pszDisplayName);
|
|
|
|
*pADsPath = AllocADsStr(ADsPath);
|
|
|
|
if (*pADsPath == NULL)
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
|
|
|
|
cleanup:
|
|
error:
|
|
|
|
if (pszDisplayName) {
|
|
FreeADsMem(pszDisplayName);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
BuildSchemaPath(
|
|
LPWSTR Parent,
|
|
LPWSTR Name,
|
|
LPWSTR Schema,
|
|
LPWSTR *pSchemaPath
|
|
)
|
|
{
|
|
WCHAR SchemaPath[MAX_PATH];
|
|
WCHAR ProviderName[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
|
|
OBJECTINFO ObjectInfo;
|
|
POBJECTINFO pObjectInfo = &ObjectInfo;
|
|
CLexer Lexer(Parent);
|
|
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
|
|
//
|
|
// We will assert if bad parameters are passed to us.
|
|
// This is because this should never be the case. This
|
|
// is an internal call
|
|
//
|
|
|
|
ADsAssert(Parent);
|
|
ADsAssert(pSchemaPath);
|
|
|
|
//
|
|
// If no schema name is passed in, then there is no schema path
|
|
//
|
|
if ( Schema == NULL || *Schema == 0 ){
|
|
|
|
*pSchemaPath = AllocADsStr(L"");
|
|
RRETURN(*pSchemaPath ? S_OK: E_OUTOFMEMORY );
|
|
}
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
hr = Object(&Lexer, pObjectInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
wsprintf(SchemaPath, L"%s://", szProviderName);
|
|
|
|
if (!pObjectInfo->NumComponents) {
|
|
if( (wcslen(Name) + wcslen(szProviderName) + 4) > MAX_PATH ) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
wcscat(SchemaPath, Name);
|
|
}else{
|
|
if( (wcslen(pObjectInfo->DisplayComponentArray[0]) +
|
|
wcslen(szProviderName) + 4) > MAX_PATH ) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
wcscat(SchemaPath, pObjectInfo->DisplayComponentArray[0]);
|
|
}
|
|
|
|
if( (wcslen(SchemaPath) + wcslen(SCHEMA_NAME) + wcslen(Schema) + 3) >
|
|
MAX_PATH ) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
wcscat( SchemaPath, L"/");
|
|
wcscat( SchemaPath, SCHEMA_NAME );
|
|
wcscat( SchemaPath, L"/");
|
|
wcscat( SchemaPath, Schema );
|
|
|
|
|
|
*pSchemaPath = AllocADsStr(SchemaPath);
|
|
hr = pSchemaPath ? S_OK: E_OUTOFMEMORY ;
|
|
|
|
error:
|
|
|
|
FreeObjectInfo( &ObjectInfo, TRUE );
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
BuildADsGuid(
|
|
REFCLSID clsid,
|
|
LPWSTR *pADsClass
|
|
)
|
|
{
|
|
WCHAR ADsClass[MAX_PATH];
|
|
|
|
if (!StringFromGUID2(clsid, ADsClass, MAX_PATH)) {
|
|
//
|
|
// MAX_PATH should be more than enough for the GUID.
|
|
//
|
|
ADsAssert(!"GUID too big !!!");
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
*pADsClass = AllocADsStr(ADsClass);
|
|
RRETURN (*pADsClass ? S_OK: E_OUTOFMEMORY);
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
MakeUncName(
|
|
LPWSTR szSrcBuffer,
|
|
LPWSTR szTargBuffer
|
|
)
|
|
{
|
|
ADsAssert(szSrcBuffer);
|
|
wcscpy(szTargBuffer, L"\\\\");
|
|
wcscat(szTargBuffer, szSrcBuffer);
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ValidateOutParameter(
|
|
BSTR * retval
|
|
)
|
|
{
|
|
if (!retval) {
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
}
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
BuildObjectInfo(
|
|
LPWSTR ADsParent,
|
|
LPWSTR Name,
|
|
POBJECTINFO * ppObjectInfo
|
|
)
|
|
{
|
|
WCHAR szBuffer[MAX_PATH];
|
|
HRESULT hr;
|
|
POBJECTINFO pObjectInfo = NULL;
|
|
|
|
//
|
|
// Both should be set in this call, cannot have a NULL parent.
|
|
//
|
|
if (!ADsParent || !*ADsParent) {
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
}
|
|
//
|
|
// We need to make sure that the path is not greater
|
|
// than MAX_PATH + 2 = 1 for / and another for \0
|
|
//
|
|
if ((wcslen(ADsParent) + wcslen(Name) + 2) > MAX_PATH) {
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
}
|
|
|
|
wcscpy(szBuffer, ADsParent);
|
|
wcscat(szBuffer, L"/");
|
|
wcscat(szBuffer, Name);
|
|
|
|
CLexer Lexer(szBuffer);
|
|
|
|
pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
|
|
if (!pObjectInfo) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
hr = Object(&Lexer, pObjectInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
*ppObjectInfo = pObjectInfo;
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
if (pObjectInfo) {
|
|
FreeObjectInfo(pObjectInfo);
|
|
}
|
|
|
|
*ppObjectInfo = NULL;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
BuildObjectInfo(
|
|
LPWSTR ADsPath,
|
|
POBJECTINFO * ppObjectInfo
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
POBJECTINFO pObjectInfo = NULL;
|
|
CLexer Lexer(ADsPath);
|
|
|
|
pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
|
|
if (!pObjectInfo) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
hr = Object(&Lexer, pObjectInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
*ppObjectInfo = pObjectInfo;
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
if (pObjectInfo) {
|
|
FreeObjectInfo(pObjectInfo);
|
|
}
|
|
|
|
*ppObjectInfo = NULL;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
MakeWinNTAccountName(
|
|
POBJECTINFO pObjectInfo,
|
|
LPWSTR szUserAccount,
|
|
BOOL fConnectToReg
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwNumComp = 0;
|
|
DWORD dwProductType = PRODTYPE_INVALID;
|
|
WCHAR szDomain[MAX_PATH];
|
|
WCHAR szSAMName[MAX_ADS_PATH];
|
|
BOOL fReplacedWithDC = FALSE;
|
|
|
|
// The credentials are needed to pass into WinNTGetCachedComputerName
|
|
CWinNTCredentials nullCredentials;
|
|
|
|
// Need szSAMName as dummy param
|
|
szSAMName[0] = L'\0';
|
|
|
|
if (!pObjectInfo || !szUserAccount)
|
|
{
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
}
|
|
|
|
dwNumComp = pObjectInfo->NumComponents;
|
|
|
|
switch (dwNumComp) {
|
|
|
|
case 2:
|
|
case 3:
|
|
|
|
//
|
|
// Check if machine is a dc
|
|
//
|
|
|
|
//
|
|
// Going to try getComputerName first as the NetWkstaGetInfo call
|
|
// times out faster than the RegConnect call we use in
|
|
// GetMachineProductType - AjayR 11-06-98.
|
|
//
|
|
|
|
if (fConnectToReg) {
|
|
|
|
if (dwNumComp==2) {
|
|
//
|
|
// we don't have domain name in pObjectInfo, let's try
|
|
// to get it from the dc name (comp[0])
|
|
//
|
|
|
|
hr = WinNTGetCachedComputerName(
|
|
pObjectInfo->ComponentArray[0],
|
|
szUserAccount,
|
|
szSAMName,
|
|
nullCredentials
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fReplacedWithDC = TRUE;
|
|
}
|
|
}
|
|
|
|
else // dwNumComp==3
|
|
{
|
|
//
|
|
// We have domain name (comp[0]) in our objectInfo, let's use
|
|
// it. Can call ValidateComputerName here, but not needed
|
|
// since error will be caught next.
|
|
//
|
|
|
|
wcscpy(szUserAccount, pObjectInfo->ComponentArray[0]);
|
|
|
|
fReplacedWithDC = TRUE;
|
|
}
|
|
|
|
if (fReplacedWithDC) {
|
|
//
|
|
// Now try connecting to make sure it is a DC
|
|
// otherwise we should not do this replacement
|
|
//
|
|
hr = GetMachineProductType(
|
|
pObjectInfo->ComponentArray[dwNumComp-2],
|
|
&dwProductType
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (dwProductType != PRODTYPE_DC) {
|
|
//
|
|
// We cannot use szUserAccount as it has
|
|
// bad info
|
|
//
|
|
fReplacedWithDC = FALSE;
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
}
|
|
|
|
}// if fConnectToReg
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
//
|
|
// Do not want to replace machine name with domain since not dc or
|
|
// dc but can't replace - best efforts fail
|
|
//
|
|
|
|
if (fReplacedWithDC==FALSE)
|
|
{
|
|
wcscpy(szUserAccount, pObjectInfo->ComponentArray[dwNumComp-2]);
|
|
}
|
|
|
|
//
|
|
// Add \UserName to account name
|
|
//
|
|
wcscat(szUserAccount, L"\\");
|
|
wcscat(szUserAccount, pObjectInfo->ComponentArray[dwNumComp-1]);
|
|
break;
|
|
|
|
default:
|
|
|
|
RRETURN(E_ADS_UNKNOWN_OBJECT);
|
|
|
|
}
|
|
|
|
|
|
error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
MakeWinNTDomainAndName(
|
|
POBJECTINFO pObjectInfo,
|
|
LPWSTR szDomName
|
|
)
|
|
{
|
|
DWORD dwNumComp = pObjectInfo->NumComponents;
|
|
|
|
switch (dwNumComp) {
|
|
case 2:
|
|
case 3:
|
|
wcscpy(szDomName, pObjectInfo->ComponentArray[dwNumComp - 2]);
|
|
wcscat(szDomName, L"\\");
|
|
wcscat(szDomName, pObjectInfo->ComponentArray[dwNumComp - 1]);
|
|
break;
|
|
|
|
default:
|
|
RRETURN(E_ADS_UNKNOWN_OBJECT);
|
|
|
|
}
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
HRESULT
|
|
ValidateObject(
|
|
DWORD dwObjectType,
|
|
POBJECTINFO pObjectInfo,
|
|
CWinNTCredentials& Credentials
|
|
)
|
|
{
|
|
ULONG uGroupType;
|
|
DWORD dwParentId;
|
|
|
|
switch (dwObjectType) {
|
|
case WINNT_USER_ID:
|
|
RRETURN(ValidateUserObject(pObjectInfo, &dwParentId, Credentials));
|
|
|
|
case WINNT_GROUP_ID:
|
|
RRETURN(ValidateGroupObject(
|
|
pObjectInfo,
|
|
&uGroupType,
|
|
&dwParentId,
|
|
Credentials
|
|
));
|
|
|
|
case WINNT_COMPUTER_ID:
|
|
RRETURN(ValidateComputerObject(pObjectInfo, Credentials));
|
|
|
|
case WINNT_PRINTER_ID:
|
|
RRETURN(ValidatePrinterObject(pObjectInfo, Credentials));
|
|
|
|
case WINNT_SERVICE_ID:
|
|
RRETURN(ValidateServiceObject(pObjectInfo, Credentials));
|
|
|
|
case WINNT_FILESHARE_ID:
|
|
RRETURN(ValidateFileShareObject(pObjectInfo, Credentials));
|
|
|
|
default:
|
|
RRETURN(E_FAIL);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FreeObjectInfo(
|
|
POBJECTINFO pObjectInfo,
|
|
BOOL fStatic
|
|
)
|
|
{
|
|
DWORD i = 0;
|
|
|
|
if (!pObjectInfo) {
|
|
return;
|
|
}
|
|
|
|
FreeADsStr( pObjectInfo->ProviderName );
|
|
|
|
for (i = 0; i < pObjectInfo->NumComponents; i++ ) {
|
|
FreeADsStr(pObjectInfo->ComponentArray[i]);
|
|
FreeADsStr(pObjectInfo->DisplayComponentArray[i]);
|
|
}
|
|
|
|
if ( !fStatic )
|
|
FreeADsMem(pObjectInfo);
|
|
}
|
|
|
|
HRESULT
|
|
CopyObjectInfo(
|
|
POBJECTINFO pSrcObjectInfo,
|
|
POBJECTINFO *pTargObjectInfo
|
|
)
|
|
{
|
|
POBJECTINFO pObjectInfo = NULL;
|
|
HRESULT hr S_OK;
|
|
DWORD i;
|
|
|
|
if(!pSrcObjectInfo){
|
|
RRETURN(S_OK);
|
|
}
|
|
pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
|
|
|
|
if (!pObjectInfo) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
|
|
pObjectInfo->ObjectType = pSrcObjectInfo->ObjectType;
|
|
pObjectInfo->NumComponents = pSrcObjectInfo->NumComponents;
|
|
pObjectInfo->ProviderName = AllocADsStr(pSrcObjectInfo->ProviderName);
|
|
|
|
for(i=0; i<pSrcObjectInfo->NumComponents; i++){
|
|
pObjectInfo->ComponentArray[i] =
|
|
AllocADsStr(pSrcObjectInfo->ComponentArray[i]);
|
|
pObjectInfo->DisplayComponentArray[i] =
|
|
AllocADsStr(pSrcObjectInfo->DisplayComponentArray[i]);
|
|
}
|
|
*pTargObjectInfo = pObjectInfo;
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
GetObjectType(
|
|
PFILTERS pFilters,
|
|
DWORD dwMaxFilters,
|
|
LPWSTR ClassName,
|
|
PDWORD pdwObjectType
|
|
)
|
|
{
|
|
DWORD i = 0;
|
|
|
|
ADsAssert(pdwObjectType);
|
|
|
|
for (i = 0; i < dwMaxFilters; i++) {
|
|
if (!_wcsicmp(ClassName, (pFilters + i)->szObjectName)) {
|
|
*pdwObjectType = (pFilters + i)->dwFilterId;
|
|
RRETURN(S_OK);
|
|
}
|
|
}
|
|
*pdwObjectType = 0;
|
|
RRETURN(E_INVALIDARG);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ValidateProvider(
|
|
POBJECTINFO pObjectInfo
|
|
)
|
|
{
|
|
|
|
//
|
|
// The provider name is case-sensitive. This is a restriction that OLE
|
|
// has put on us.
|
|
//
|
|
if (!(wcscmp(pObjectInfo->ProviderName, szProviderName))) {
|
|
RRETURN(S_OK);
|
|
}
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetDomainFromPath(
|
|
LPTSTR ADsPath,
|
|
LPTSTR szDomainName
|
|
)
|
|
{
|
|
OBJECTINFO ObjectInfo;
|
|
POBJECTINFO pObjectInfo = &ObjectInfo;
|
|
CLexer Lexer(ADsPath);
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//assumption: Valid strings are passed to GetDomainFromPath
|
|
|
|
ADsAssert(ADsPath);
|
|
ADsAssert(szDomainName);
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
hr = Object(&Lexer, pObjectInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
if (pObjectInfo->NumComponents) {
|
|
wcscpy(szDomainName, pObjectInfo->ComponentArray[0]);
|
|
}else {
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
error:
|
|
|
|
FreeObjectInfo( &ObjectInfo, TRUE );
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
GetServerFromPath(
|
|
LPTSTR ADsPath,
|
|
LPTSTR szServerName
|
|
)
|
|
{
|
|
OBJECTINFO ObjectInfo;
|
|
POBJECTINFO pObjectInfo = &ObjectInfo;
|
|
CLexer Lexer(ADsPath);
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//assumption: Valid strings are passed to GetDomainFromPath
|
|
|
|
ADsAssert(ADsPath);
|
|
ADsAssert(szServerName);
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
hr = Object(&Lexer, pObjectInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
if (pObjectInfo->NumComponents > 1) {
|
|
wcscpy(szServerName, pObjectInfo->ComponentArray[1]);
|
|
}else {
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
error:
|
|
|
|
FreeObjectInfo( &ObjectInfo, TRUE );
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
TickCountDiff(
|
|
DWORD dwTime1,
|
|
DWORD dwTime2
|
|
)
|
|
{
|
|
//
|
|
// does dwTime1 - dwTime2 and takes care of wraparound.
|
|
// The first time must be later than the second
|
|
// Restriction:: The two times must have been taken not more than
|
|
// 49.7 days apart
|
|
//
|
|
|
|
DWORD dwRetval;
|
|
|
|
if(dwTime1 >= dwTime2){
|
|
dwRetval = dwTime1 - dwTime2;
|
|
}
|
|
|
|
else{
|
|
dwRetval = dwTime2 - dwTime1;
|
|
dwRetval = MAX_DWORD - dwRetval;
|
|
}
|
|
return dwRetval;
|
|
}
|
|
|
|
HRESULT
|
|
DelimitedStringToVariant(
|
|
LPTSTR pszString,
|
|
VARIANT *pvar,
|
|
TCHAR Delimiter
|
|
)
|
|
{
|
|
SAFEARRAYBOUND sabound[1];
|
|
DWORD dwElements;
|
|
LPTSTR pszCurrPos = pszString;
|
|
LPTSTR *rgszStrings = NULL;
|
|
SAFEARRAY *psa = NULL;
|
|
VARIANT v;
|
|
HRESULT hr = S_OK;
|
|
LONG i;
|
|
|
|
//
|
|
// This function converts a delimited string into a VARIANT of
|
|
// safe arrays.
|
|
//
|
|
// Assumption: a valid string are passed to this function
|
|
// note that the input string gets destroyed in the process
|
|
//
|
|
|
|
//
|
|
// scan the delimited string once to find out the dimension
|
|
//
|
|
|
|
//
|
|
// in order to filter for NULL input values do a sanity check for
|
|
// length of input string.
|
|
//
|
|
|
|
|
|
if (!pszString){
|
|
sabound[0].cElements = 0;
|
|
sabound[0].lLbound = 0;
|
|
|
|
psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
|
|
|
|
if (psa == NULL){
|
|
hr = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
VariantInit(pvar);
|
|
V_VT(pvar) = VT_ARRAY|VT_VARIANT;
|
|
V_ARRAY(pvar) = psa;
|
|
goto error;
|
|
}
|
|
|
|
dwElements = (wcslen(pszString) == 0) ? 0: 1 ;
|
|
|
|
while(!(*pszCurrPos == TEXT('\0'))){
|
|
if(*pszCurrPos == Delimiter){
|
|
dwElements++;
|
|
*pszCurrPos = TEXT('\0');
|
|
}
|
|
pszCurrPos++;
|
|
}
|
|
|
|
rgszStrings = (LPTSTR *)AllocADsMem(sizeof(LPTSTR)*dwElements);
|
|
|
|
if(!rgszStrings){
|
|
hr = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// scan string again and put the appropriate pointers
|
|
//
|
|
|
|
pszCurrPos = pszString;
|
|
if(rgszStrings != NULL){
|
|
(*rgszStrings) = pszCurrPos;
|
|
}
|
|
i = 1;
|
|
|
|
while(i < (LONG)dwElements){
|
|
|
|
if(*pszCurrPos == TEXT('\0')){
|
|
*(rgszStrings+i) = ++pszCurrPos;
|
|
i++;
|
|
}
|
|
pszCurrPos++;
|
|
}
|
|
|
|
|
|
//
|
|
// create the safearray
|
|
//
|
|
|
|
sabound[0].cElements = dwElements;
|
|
sabound[0].lLbound = 0;
|
|
|
|
psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
|
|
|
|
if (psa == NULL){
|
|
hr = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
|
|
for(i=0; i<(LONG)dwElements; i++){
|
|
|
|
VariantInit(&v);
|
|
V_VT(&v) = VT_BSTR;
|
|
|
|
hr = ADsAllocString(*(rgszStrings+i), &(V_BSTR(&v)));
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Stick the caller provided data into the end of the SafeArray
|
|
//
|
|
|
|
hr = SafeArrayPutElement(psa, &i, &v);
|
|
VariantClear(&v);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
//
|
|
// convert this safearray into a VARIANT
|
|
//
|
|
|
|
VariantInit(pvar);
|
|
V_VT(pvar) = VT_ARRAY|VT_VARIANT;
|
|
V_ARRAY(pvar) = psa;
|
|
|
|
error:
|
|
if(rgszStrings && dwElements != 0){
|
|
FreeADsMem(rgszStrings);
|
|
}
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
BuildComputerFromObjectInfo(
|
|
POBJECTINFO pObjectInfo,
|
|
LPTSTR pszADsPath
|
|
)
|
|
{
|
|
|
|
if(!pObjectInfo){
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
if(pObjectInfo->NumComponents == 3) {
|
|
|
|
wsprintf(
|
|
pszADsPath,
|
|
L"%s://%s/%s",
|
|
pObjectInfo->ProviderName,
|
|
pObjectInfo->ComponentArray[0],
|
|
pObjectInfo->ComponentArray[1]
|
|
);
|
|
|
|
} else if (pObjectInfo->NumComponents == 2){
|
|
|
|
wsprintf(
|
|
pszADsPath,
|
|
L"%s://%s",
|
|
pObjectInfo->ProviderName,
|
|
pObjectInfo->ComponentArray[0]
|
|
);
|
|
|
|
} else {
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
RRETURN(S_OK);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
FPNWSERVERADDRtoString(
|
|
FPNWSERVERADDR WkstaAddress,
|
|
LPWSTR * ppszString
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
TCHAR szNibble[2]; //one number and a null termination
|
|
USHORT usNibble;
|
|
int i;
|
|
TCHAR szWkstaAddr[MAX_PATH];
|
|
|
|
//
|
|
// assumption: valid input values are passed to this function.
|
|
//
|
|
|
|
//
|
|
// First 4 bytes is network address, then a dot and then bytes 5-10
|
|
// are physical node address. Each byte consumes 2 chars space.
|
|
// Then a byte for TEXT('\0')
|
|
//
|
|
|
|
_tcscpy(szWkstaAddr, TEXT(""));
|
|
|
|
for( i=0; i < 4; i++){
|
|
|
|
usNibble = WkstaAddress[i] & 0xF0;
|
|
usNibble = usNibble >> 4;
|
|
_itot(usNibble, szNibble, 16 );
|
|
_tcscat(szWkstaAddr, szNibble);
|
|
usNibble = WkstaAddress[i] & 0xF;
|
|
_itot(usNibble, szNibble, 16 );
|
|
_tcscat(szWkstaAddr, szNibble);
|
|
|
|
}
|
|
|
|
_tcscat(szWkstaAddr, TEXT("."));
|
|
|
|
for(i=4; i<10 ; i++){
|
|
|
|
usNibble = WkstaAddress[i] & 0xF0;
|
|
usNibble = usNibble >> 4;
|
|
_itot(usNibble, szNibble, 16 );
|
|
_tcscat(szWkstaAddr, szNibble);
|
|
usNibble = WkstaAddress[i] & 0xF;
|
|
_itot(usNibble, szNibble, 16 );
|
|
_tcscat(szWkstaAddr, szNibble);
|
|
}
|
|
|
|
*ppszString = AllocADsStr(szWkstaAddr);
|
|
|
|
if(!*ppszString){
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
PKEYDATA
|
|
CreateTokenList(
|
|
LPWSTR pKeyData
|
|
)
|
|
{
|
|
DWORD cTokens;
|
|
DWORD cb;
|
|
PKEYDATA pResult;
|
|
LPWSTR pDest;
|
|
LPWSTR psz = pKeyData;
|
|
LPWSTR *ppToken;
|
|
|
|
if (!psz || !*psz)
|
|
return NULL;
|
|
|
|
cTokens=1;
|
|
|
|
// Scan through the string looking for commas,
|
|
// ensuring that each is followed by a non-NULL character:
|
|
|
|
while ((psz = wcschr(psz, L',')) && psz[1]) {
|
|
|
|
cTokens++;
|
|
psz++;
|
|
}
|
|
|
|
cb = sizeof(KEYDATA) + (cTokens-1) * sizeof(LPWSTR) +
|
|
wcslen(pKeyData)*sizeof(WCHAR) + sizeof(WCHAR);
|
|
|
|
if (!(pResult = (PKEYDATA)AllocADsMem(cb)))
|
|
return NULL;
|
|
|
|
// Initialise pDest to point beyond the token pointers:
|
|
|
|
pDest = (LPWSTR)((LPBYTE)pResult + sizeof(KEYDATA) +
|
|
(cTokens-1) * sizeof(LPWSTR));
|
|
|
|
// Then copy the key data buffer there:
|
|
|
|
wcscpy(pDest, pKeyData);
|
|
|
|
ppToken = pResult->pTokens;
|
|
|
|
|
|
// Remember, wcstok has the side effect of replacing the delimiter
|
|
// by NULL, which is precisely what we want:
|
|
|
|
psz = wcstok (pDest, L",");
|
|
|
|
while (psz) {
|
|
|
|
*ppToken++ = psz;
|
|
psz = wcstok (NULL, L",");
|
|
}
|
|
|
|
pResult->cTokens = cTokens;
|
|
|
|
return( pResult );
|
|
}
|
|
|
|
STDMETHODIMP
|
|
GenericGetPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
THIS_ BSTR bstrName,
|
|
VARIANT FAR* pvProp
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId;
|
|
DWORD dwNumValues;
|
|
DWORD dwInfoLevel;
|
|
LPNTOBJECT pNtSrcObjects = NULL;
|
|
|
|
//
|
|
// For those who know no not what they do
|
|
//
|
|
if (!pvProp) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// retrieve data object from cache; if one exists
|
|
|
|
hr = pPropertyCache->getproperty(
|
|
bstrName,
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// translate the Nt objects to variants
|
|
//
|
|
|
|
if (dwNumValues == 1) {
|
|
|
|
hr = NtTypeToVarTypeCopy(
|
|
pNtSrcObjects,
|
|
pvProp
|
|
);
|
|
|
|
}else {
|
|
|
|
hr = NtTypeToVarTypeCopyConstruct(
|
|
pNtSrcObjects,
|
|
dwNumValues,
|
|
pvProp
|
|
);
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pNtSrcObjects) {
|
|
|
|
NTTypeFreeNTObjects(
|
|
pNtSrcObjects,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
GenericPutPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
PPROPERTYINFO pSchemaProps,
|
|
DWORD dwSchemaPropSize,
|
|
THIS_ BSTR bstrName,
|
|
VARIANT vProp,
|
|
BOOL fCheckSchemaWriteAccess
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId = 0;
|
|
DWORD dwIndex = 0;
|
|
LPNTOBJECT pNtDestObjects = NULL;
|
|
|
|
VARIANT * pVarArray = NULL;
|
|
VARIANT * pvProp = NULL;
|
|
DWORD dwNumValues = 0;
|
|
|
|
|
|
//
|
|
// check if property in schema and get syntax of property
|
|
//
|
|
|
|
hr = ValidatePropertyinSchemaClass(
|
|
pSchemaProps,
|
|
dwSchemaPropSize,
|
|
bstrName,
|
|
&dwSyntaxId
|
|
);
|
|
|
|
if(TRUE == fCheckSchemaWriteAccess) {
|
|
//
|
|
// check if this is a writeable property in the schema
|
|
//
|
|
|
|
hr = ValidateIfWriteableProperty(
|
|
pSchemaProps,
|
|
dwSchemaPropSize,
|
|
bstrName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// Issue: How do we handle multi-valued support
|
|
//
|
|
|
|
//
|
|
// A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
|
|
// We should dereference a VT_BYREF|VT_VARIANT once and see
|
|
// what's inside.
|
|
//
|
|
pvProp = &vProp;
|
|
if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
|
|
pvProp = V_VARIANTREF(&vProp);
|
|
}
|
|
|
|
if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
|
|
(V_VT(&vProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
|
|
|
|
hr = ConvertByRefSafeArrayToVariantArray(
|
|
*pvProp,
|
|
&pVarArray,
|
|
&dwNumValues
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if( (0 == dwNumValues) && (NULL == pVarArray) ) {
|
|
// return error if the safearray had no elements. Otherwise, the
|
|
// NT object stored in the property cache is garbage.
|
|
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
|
|
}
|
|
|
|
pvProp = pVarArray;
|
|
|
|
}else {
|
|
|
|
dwNumValues = 1;
|
|
}
|
|
|
|
|
|
hr = VarTypeToNtTypeCopyConstruct(
|
|
dwSyntaxId,
|
|
pvProp,
|
|
dwNumValues,
|
|
&pNtDestObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Find this property in the cache
|
|
//
|
|
|
|
hr = pPropertyCache->findproperty(
|
|
bstrName,
|
|
&dwIndex
|
|
);
|
|
|
|
//
|
|
// If this property does not exist in the
|
|
// cache, add this property into the cache.
|
|
//
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
hr = pPropertyCache->addproperty(
|
|
bstrName,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pNtDestObjects
|
|
);
|
|
//
|
|
// If the operation fails for some reason
|
|
// move on to the next property
|
|
//
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
//
|
|
// Now update the property in the cache
|
|
//
|
|
|
|
hr = pPropertyCache->putproperty(
|
|
bstrName,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pNtDestObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pNtDestObjects) {
|
|
NTTypeFreeNTObjects(
|
|
pNtDestObjects,
|
|
dwNumValues
|
|
);
|
|
|
|
}
|
|
|
|
|
|
if (pVarArray) {
|
|
|
|
DWORD i = 0;
|
|
|
|
for (i = 0; i < dwNumValues; i++) {
|
|
VariantClear(pVarArray + i);
|
|
}
|
|
FreeADsMem(pVarArray);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
GenericGetExPropertyManager(
|
|
DWORD dwObjectState,
|
|
CPropertyCache * pPropertyCache,
|
|
THIS_ BSTR bstrName,
|
|
VARIANT FAR* pvProp
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId;
|
|
DWORD dwNumValues;
|
|
LPNTOBJECT pNtSrcObjects = NULL;
|
|
|
|
//
|
|
// retrieve data object from cache; if one exis
|
|
//
|
|
|
|
if (dwObjectState == ADS_OBJECT_UNBOUND) {
|
|
|
|
hr = pPropertyCache->unboundgetproperty(
|
|
bstrName,
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = pPropertyCache->getproperty(
|
|
bstrName,
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// translate the Nds objects to variants
|
|
//
|
|
|
|
hr = NtTypeToVarTypeCopyConstruct(
|
|
pNtSrcObjects,
|
|
dwNumValues,
|
|
pvProp
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
if (pNtSrcObjects) {
|
|
|
|
NTTypeFreeNTObjects(
|
|
pNtSrcObjects,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
GenericPutExPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
PPROPERTYINFO pSchemaProps,
|
|
DWORD dwSchemaPropSize,
|
|
THIS_ BSTR bstrName,
|
|
VARIANT vProp
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId = 0;
|
|
DWORD dwIndex = 0;
|
|
LPNTOBJECT pNtDestObjects = NULL;
|
|
|
|
VARIANT * pVarArray = NULL;
|
|
VARIANT * pvProp = NULL;
|
|
DWORD dwNumValues = 0;
|
|
|
|
|
|
//
|
|
// check if property in schema and get syntax of property
|
|
//
|
|
|
|
hr = ValidatePropertyinSchemaClass(
|
|
pSchemaProps,
|
|
dwSchemaPropSize,
|
|
bstrName,
|
|
&dwSyntaxId
|
|
);
|
|
|
|
//
|
|
// check if this is a writeable property in the schema
|
|
//
|
|
|
|
hr = ValidateIfWriteableProperty(
|
|
pSchemaProps,
|
|
dwSchemaPropSize,
|
|
bstrName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// Issue: How do we handle multi-valued support
|
|
//
|
|
|
|
//
|
|
// A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
|
|
// We should dereference a VT_BYREF|VT_VARIANT once and see
|
|
// what's inside.
|
|
//
|
|
pvProp = &vProp;
|
|
if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
|
|
pvProp = V_VARIANTREF(&vProp);
|
|
}
|
|
|
|
if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
|
|
(V_VT(&vProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
|
|
|
|
hr = ConvertByRefSafeArrayToVariantArray(
|
|
*pvProp,
|
|
&pVarArray,
|
|
&dwNumValues
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if( (0 == dwNumValues) && (NULL == pVarArray) ) {
|
|
// return error if the safearray had no elements. Otherwise, the
|
|
// NT object stored in the property cache is garbage.
|
|
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
|
|
}
|
|
|
|
pvProp = pVarArray;
|
|
|
|
}else {
|
|
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// check if the variant maps to the syntax of this property
|
|
//
|
|
|
|
hr = VarTypeToNtTypeCopyConstruct(
|
|
dwSyntaxId,
|
|
pvProp,
|
|
dwNumValues,
|
|
&pNtDestObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Find this property in the cache
|
|
//
|
|
|
|
hr = pPropertyCache->findproperty(
|
|
bstrName,
|
|
&dwIndex
|
|
);
|
|
|
|
//
|
|
// If this property does not exist in the
|
|
// cache, add this property into the cache.
|
|
//
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
hr = pPropertyCache->addproperty(
|
|
bstrName,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pNtDestObjects
|
|
);
|
|
//
|
|
// If the operation fails for some reason
|
|
// move on to the next property
|
|
//
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
//
|
|
// Now update the property in the cache
|
|
//
|
|
|
|
hr = pPropertyCache->putproperty(
|
|
bstrName,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pNtDestObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pNtDestObjects) {
|
|
NTTypeFreeNTObjects(
|
|
pNtDestObjects,
|
|
dwNumValues
|
|
);
|
|
|
|
}
|
|
|
|
if (pVarArray) {
|
|
|
|
DWORD i = 0;
|
|
|
|
for (i = 0; i < dwNumValues; i++) {
|
|
VariantClear(pVarArray + i);
|
|
}
|
|
FreeADsMem(pVarArray);
|
|
}
|
|
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
DWORD
|
|
DelimitedStrSize(
|
|
LPWSTR pszString,
|
|
WCHAR Delimiter
|
|
)
|
|
{
|
|
|
|
DWORD dwElements = (wcslen(pszString) == 0) ? 0: 1 ;
|
|
LPTSTR pszCurrPos = pszString;
|
|
|
|
if (!pszString || !*pszString) {
|
|
return dwElements;
|
|
}
|
|
|
|
while(!(*pszCurrPos == TEXT('\0'))){
|
|
|
|
if(*pszCurrPos == Delimiter){
|
|
dwElements++;
|
|
*pszCurrPos = TEXT('\0');
|
|
}
|
|
|
|
pszCurrPos++;
|
|
}
|
|
|
|
return dwElements;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
NulledStrSize(
|
|
LPWSTR pszString
|
|
)
|
|
{
|
|
|
|
|
|
DWORD dwElements = 0;
|
|
LPTSTR pszCurrPos = pszString;
|
|
BOOL foundNULL = FALSE;
|
|
|
|
if (!pszString || !*pszString) {
|
|
return dwElements;
|
|
}
|
|
|
|
while(!(*pszCurrPos == TEXT('\0') && foundNULL== TRUE)){
|
|
|
|
if(*pszCurrPos == TEXT('\0')){
|
|
dwElements++;
|
|
foundNULL = TRUE;
|
|
} else {
|
|
foundNULL = FALSE;
|
|
}
|
|
|
|
pszCurrPos++;
|
|
}
|
|
|
|
return dwElements;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
GenericPropCountPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
PLONG plCount
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (pPropertyCache) {
|
|
hr = pPropertyCache->get_PropertyCount((PDWORD)plCount);
|
|
}
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
GenericNextPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
VARIANT FAR *pVariant
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DWORD dwSyntaxId = 0;
|
|
DWORD dwNumValues = 0;
|
|
LPNTOBJECT pNtSrcObjects = NULL;
|
|
VARIANT varData;
|
|
IDispatch * pDispatch = NULL;
|
|
|
|
VariantInit(&varData);
|
|
|
|
hr = pPropertyCache->unboundgetproperty(
|
|
pPropertyCache->get_CurrentIndex(),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// translate the Nt objects to variants
|
|
//
|
|
|
|
hr = ConvertNtValuesToVariant(
|
|
pPropertyCache->get_CurrentPropName(),
|
|
pNtSrcObjects,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
|
//
|
|
// - goto next one even if error to avoid infinite looping at a property
|
|
// which we cannot convert (e.g. schemaless server property.)
|
|
// - do not return the result of Skip() as current operation does not
|
|
// depend on the sucess of Skip().
|
|
//
|
|
|
|
pPropertyCache->skip_propindex(
|
|
1
|
|
);
|
|
|
|
if (pNtSrcObjects) {
|
|
|
|
NTTypeFreeNTObjects(
|
|
pNtSrcObjects,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GenericSkipPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
ULONG cElements
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
hr = pPropertyCache->skip_propindex(
|
|
cElements
|
|
);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
GenericResetPropertyManager(
|
|
CPropertyCache * pPropertyCache
|
|
)
|
|
{
|
|
pPropertyCache->reset_propindex();
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
HRESULT
|
|
GenericDeletePropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
VARIANT varEntry
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndex = 0;
|
|
|
|
switch (V_VT(&varEntry)) {
|
|
|
|
case VT_BSTR:
|
|
|
|
hr = pPropertyCache->findproperty(
|
|
V_BSTR(&varEntry),
|
|
&dwIndex
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
break;
|
|
|
|
case VT_I4:
|
|
dwIndex = V_I4(&varEntry);
|
|
break;
|
|
|
|
|
|
case VT_I2:
|
|
dwIndex = V_I2(&varEntry);
|
|
break;
|
|
|
|
|
|
default:
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = pPropertyCache->deleteproperty(
|
|
dwIndex
|
|
);
|
|
error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GenericPutPropItemPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
PPROPERTYINFO pSchemaProps,
|
|
DWORD dwSchemaPropSize,
|
|
VARIANT varData
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId = 0;
|
|
DWORD dwIndex = 0;
|
|
WCHAR szPropertyName[MAX_PATH] = L"";
|
|
LPNTOBJECT pNtDestObjects = NULL;
|
|
DWORD dwNumValues = 0;
|
|
DWORD dwControlCode = 0;
|
|
|
|
|
|
|
|
hr = ConvertVariantToNtValues(
|
|
varData,
|
|
pSchemaProps,
|
|
dwSchemaPropSize,
|
|
szPropertyName,
|
|
&pNtDestObjects,
|
|
&dwNumValues,
|
|
&dwSyntaxId,
|
|
&dwControlCode
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (dwControlCode != ADS_PROPERTY_UPDATE) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
|
|
}
|
|
|
|
|
|
//
|
|
// check if this is a writeable property in the schema
|
|
//
|
|
|
|
hr = ValidateIfWriteableProperty(
|
|
pSchemaProps,
|
|
dwSchemaPropSize,
|
|
szPropertyName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// Find this property in the cache
|
|
//
|
|
|
|
hr = pPropertyCache->findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
|
|
//
|
|
// If this property does not exist in the
|
|
// cache, add this property into the cache.
|
|
//
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
hr = pPropertyCache->addproperty(
|
|
szPropertyName,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pNtDestObjects
|
|
);
|
|
//
|
|
// If the operation fails for some reason
|
|
// move on to the next property
|
|
//
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
//
|
|
// Now update the property in the cache
|
|
//
|
|
|
|
hr = pPropertyCache->putproperty(
|
|
szPropertyName,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pNtDestObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pNtDestObjects) {
|
|
NTTypeFreeNTObjects(
|
|
pNtDestObjects,
|
|
dwNumValues
|
|
);
|
|
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
GenericGetPropItemPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
DWORD dwObjectState,
|
|
BSTR bstrName,
|
|
LONG lnADsType,
|
|
VARIANT * pVariant
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId;
|
|
DWORD dwNumValues;
|
|
LPNTOBJECT pNtSrcObjects = NULL;
|
|
|
|
//
|
|
// retrieve data object from cache; if one exis
|
|
//
|
|
|
|
if (dwObjectState == ADS_OBJECT_UNBOUND) {
|
|
|
|
hr = pPropertyCache->unboundgetproperty(
|
|
bstrName,
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = pPropertyCache->getproperty(
|
|
bstrName,
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// translate the Nds objects to variants
|
|
//
|
|
|
|
hr = ConvertNtValuesToVariant(
|
|
bstrName,
|
|
pNtSrcObjects,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
if (pNtSrcObjects) {
|
|
|
|
NTTypeFreeNTObjects(
|
|
pNtSrcObjects,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
GenericItemPropertyManager(
|
|
CPropertyCache * pPropertyCache,
|
|
DWORD dwObjectState,
|
|
VARIANT varIndex,
|
|
VARIANT *pVariant
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId;
|
|
DWORD dwNumValues;
|
|
LPNTOBJECT pNtSrcObjects = NULL;
|
|
LPWSTR szPropName = NULL;
|
|
VARIANT *pvVar = &varIndex;
|
|
|
|
//
|
|
// retrieve data object from cache; if one exis
|
|
//
|
|
|
|
if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
|
|
//
|
|
// The value is being passed in byref so we need to
|
|
// deref it for vbs stuff to work
|
|
//
|
|
pvVar = V_VARIANTREF(&varIndex);
|
|
}
|
|
|
|
switch (V_VT(pvVar)) {
|
|
|
|
case VT_BSTR:
|
|
if (dwObjectState == ADS_OBJECT_UNBOUND) {
|
|
|
|
hr = pPropertyCache->unboundgetproperty(
|
|
V_BSTR(pvVar),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = pPropertyCache->getproperty(
|
|
V_BSTR(pvVar),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = ConvertNtValuesToVariant(
|
|
V_BSTR(pvVar),
|
|
pNtSrcObjects,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
break;
|
|
|
|
|
|
case VT_I4:
|
|
|
|
hr = pPropertyCache->unboundgetproperty(
|
|
V_I4(pvVar),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
szPropName = pPropertyCache->get_PropName(V_I4(pvVar));
|
|
|
|
hr = ConvertNtValuesToVariant(
|
|
szPropName,
|
|
pNtSrcObjects,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
break;
|
|
|
|
|
|
case VT_I2:
|
|
|
|
hr = pPropertyCache->unboundgetproperty(
|
|
(DWORD)V_I2(pvVar),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNtSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
szPropName = pPropertyCache->get_PropName(V_I2(pvVar));
|
|
|
|
hr = ConvertNtValuesToVariant(
|
|
szPropName,
|
|
pNtSrcObjects,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
break;
|
|
|
|
|
|
default:
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
|
|
error:
|
|
if (pNtSrcObjects) {
|
|
|
|
NTTypeFreeNTObjects(
|
|
pNtSrcObjects,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GenericPurgePropertyManager(
|
|
CPropertyCache * pPropertyCache
|
|
)
|
|
{
|
|
pPropertyCache->flushpropcache();
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CreatePropEntry(
|
|
LPWSTR szPropName,
|
|
ADSTYPE dwADsType,
|
|
VARIANT varData,
|
|
REFIID riid,
|
|
LPVOID * ppDispatch
|
|
)
|
|
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IADsPropertyEntry * pPropEntry = NULL;
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_PropertyEntry,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IADsPropertyEntry,
|
|
(void **)&pPropEntry
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
hr = pPropEntry->put_Name(szPropName);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pPropEntry->put_Values(varData);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pPropEntry->put_ADsType(dwADsType);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// no control code
|
|
|
|
hr = pPropEntry->QueryInterface(
|
|
riid,
|
|
ppDispatch
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
error:
|
|
|
|
if (pPropEntry) {
|
|
pPropEntry->Release();
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
ConvertNtValuesToVariant(
|
|
LPWSTR szPropertyName,
|
|
PNTOBJECT pNtSrcObject,
|
|
DWORD dwNumValues,
|
|
PVARIANT pVariant
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
VARIANT varData;
|
|
IDispatch * pDispatch = NULL;
|
|
PADSVALUE pAdsValues = NULL;
|
|
ADSTYPE dwADsType = ADSTYPE_INVALID;
|
|
|
|
VariantInit(&varData);
|
|
VariantInit(pVariant);
|
|
|
|
if (dwNumValues>0) {
|
|
|
|
hr = NTTypeToAdsTypeCopyConstruct(
|
|
pNtSrcObject,
|
|
dwNumValues,
|
|
&pAdsValues
|
|
);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
hr = AdsTypeToPropVariant(
|
|
pAdsValues,
|
|
dwNumValues,
|
|
&varData
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwADsType = pAdsValues->dwType;
|
|
}
|
|
|
|
else if (hr==E_OUTOFMEMORY) {
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// failed because of NTType is not supported yet (e.g DelimitedString)
|
|
// in NTTypeToAdsTypeCopyConstruct() conversion
|
|
// -> use empty variant now.
|
|
//
|
|
else {
|
|
|
|
VariantInit(&varData);
|
|
}
|
|
}
|
|
|
|
hr = CreatePropEntry(
|
|
szPropertyName,
|
|
dwADsType,
|
|
varData,
|
|
IID_IDispatch,
|
|
(void **)&pDispatch
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
V_DISPATCH(pVariant) = pDispatch;
|
|
V_VT(pVariant) = VT_DISPATCH;
|
|
|
|
|
|
error:
|
|
|
|
VariantClear(&varData);
|
|
|
|
if (pAdsValues) {
|
|
AdsFreeAdsValues(
|
|
pAdsValues,
|
|
dwNumValues
|
|
);
|
|
FreeADsMem( pAdsValues );
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
ConvertVariantToVariantArray(
|
|
VARIANT varData,
|
|
VARIANT ** ppVarArray,
|
|
DWORD * pdwNumValues
|
|
)
|
|
{
|
|
DWORD dwNumValues = 0;
|
|
VARIANT * pVarArray = NULL;
|
|
HRESULT hr = S_OK;
|
|
VARIANT * pVarData = NULL;
|
|
|
|
*ppVarArray = NULL;
|
|
*pdwNumValues = 0;
|
|
|
|
//
|
|
// A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
|
|
// We should dereference a VT_BYREF|VT_VARIANT once and see
|
|
// what's inside.
|
|
//
|
|
pVarData = &varData;
|
|
if (V_VT(pVarData) == (VT_BYREF|VT_VARIANT)) {
|
|
pVarData = V_VARIANTREF(&varData);
|
|
}
|
|
|
|
if ((V_VT(pVarData) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
|
|
(V_VT(&varData) == (VT_VARIANT|VT_ARRAY))) {
|
|
|
|
hr = ConvertSafeArrayToVariantArray(
|
|
*pVarData,
|
|
&pVarArray,
|
|
&dwNumValues
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
} else {
|
|
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
*ppVarArray = pVarArray;
|
|
*pdwNumValues = dwNumValues;
|
|
|
|
error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
void
|
|
FreeVariantArray(
|
|
VARIANT * pVarArray,
|
|
DWORD dwNumValues
|
|
)
|
|
{
|
|
if (pVarArray) {
|
|
|
|
DWORD i = 0;
|
|
|
|
for (i = 0; i < dwNumValues; i++) {
|
|
VariantClear(pVarArray + i);
|
|
}
|
|
FreeADsMem(pVarArray);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
ConvertVariantToNtValues(
|
|
VARIANT varData,
|
|
PPROPERTYINFO pSchemaProps,
|
|
DWORD dwSchemaPropSize,
|
|
LPWSTR szPropertyName,
|
|
PNTOBJECT *ppNtDestObjects,
|
|
PDWORD pdwNumValues,
|
|
PDWORD pdwSyntaxId,
|
|
PDWORD pdwControlCode
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IADsPropertyEntry * pPropEntry = NULL;
|
|
IDispatch * pDispatch = NULL;
|
|
BSTR bstrPropName = NULL;
|
|
DWORD dwControlCode = 0;
|
|
DWORD dwAdsType = 0;
|
|
VARIANT varValues;
|
|
VARIANT * pVarArray = NULL;
|
|
DWORD dwNumValues = 0;
|
|
PADSVALUE pAdsValues = NULL;
|
|
DWORD dwAdsValues = 0;
|
|
|
|
PNTOBJECT pNtDestObjects = 0;
|
|
DWORD dwNumNtObjects = 0;
|
|
DWORD dwNtSyntaxId = 0;
|
|
|
|
if (V_VT(&varData) != VT_DISPATCH) {
|
|
RRETURN (hr = DISP_E_TYPEMISMATCH);
|
|
}
|
|
|
|
pDispatch = V_DISPATCH(&varData);
|
|
|
|
hr = pDispatch->QueryInterface(
|
|
IID_IADsPropertyEntry,
|
|
(void **)&pPropEntry
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
VariantInit(&varValues);
|
|
VariantClear(&varValues);
|
|
|
|
|
|
hr = pPropEntry->get_Name(&bstrPropName);
|
|
BAIL_ON_FAILURE(hr);
|
|
if(wcslen(bstrPropName) < MAX_PATH)
|
|
wcscpy(szPropertyName, bstrPropName);
|
|
else {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
hr = pPropEntry->get_ControlCode((long *)&dwControlCode);
|
|
BAIL_ON_FAILURE(hr);
|
|
*pdwControlCode = dwControlCode;
|
|
|
|
hr = pPropEntry->get_ADsType((long *)&dwAdsType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pPropEntry->get_Values(&varValues);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ConvertVariantToVariantArray(
|
|
varValues,
|
|
&pVarArray,
|
|
&dwNumValues
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (dwNumValues) {
|
|
hr = PropVariantToAdsType(
|
|
pVarArray,
|
|
dwNumValues,
|
|
&pAdsValues,
|
|
&dwAdsValues
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = AdsTypeToNTTypeCopyConstruct(
|
|
pAdsValues,
|
|
dwAdsValues,
|
|
&pNtDestObjects,
|
|
&dwNumNtObjects,
|
|
&dwNtSyntaxId
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
*pdwNumValues = dwNumValues;
|
|
*ppNtDestObjects = pNtDestObjects;
|
|
*pdwSyntaxId = dwNtSyntaxId;
|
|
|
|
error:
|
|
|
|
if (pVarArray) {
|
|
FreeVariantArray(
|
|
pVarArray,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
if (pPropEntry) {
|
|
pPropEntry->Release();
|
|
}
|
|
VariantClear(&varValues);
|
|
|
|
if (pAdsValues) {
|
|
AdsFreeAdsValues(
|
|
pAdsValues,
|
|
dwAdsValues
|
|
);
|
|
FreeADsMem( pAdsValues );
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetMachineProductType(
|
|
IN LPTSTR pszServer,
|
|
OUT PRODUCTTYPE *pdwProductType
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
LONG dwStatus;
|
|
HKEY hkLocalMachine = NULL;
|
|
HKEY hkProductOptions = NULL;
|
|
DWORD dwValueType;
|
|
WCHAR szData[20];
|
|
DWORD dwDataSize = sizeof(szData);
|
|
|
|
|
|
//
|
|
// pszServer can be NULL for local server
|
|
//
|
|
if (!pdwProductType)
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
*pdwProductType = PRODTYPE_INVALID;
|
|
|
|
|
|
//
|
|
// Connect to remote's machine registry
|
|
//
|
|
dwStatus = RegConnectRegistry(
|
|
pszServer,
|
|
HKEY_LOCAL_MACHINE,
|
|
&hkLocalMachine
|
|
);
|
|
|
|
if (dwStatus != ERROR_SUCCESS)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwStatus);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// Open key ProductOptions
|
|
//
|
|
dwStatus = RegOpenKeyEx(
|
|
hkLocalMachine,
|
|
L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hkProductOptions
|
|
);
|
|
|
|
if (dwStatus != ERROR_SUCCESS)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwStatus);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// Get Value of Product Type
|
|
//
|
|
dwStatus = RegQueryValueEx(
|
|
hkProductOptions,
|
|
L"ProductType",
|
|
NULL,
|
|
&dwValueType,
|
|
(LPBYTE) szData,
|
|
&dwDataSize
|
|
);
|
|
|
|
|
|
//
|
|
// check server type
|
|
//
|
|
if (_wcsicmp(szData, WINNT_A_LANMANNT_W)==0)
|
|
{
|
|
*pdwProductType = PRODTYPE_DC;
|
|
}
|
|
else if (_wcsicmp(szData, WINNT_A_SERVERNT_W)==0)
|
|
{
|
|
*pdwProductType = PRODTYPE_STDALONESVR;
|
|
}
|
|
else if (_wcsicmp(szData, WINNT_A_WINNT_W)==0)
|
|
{
|
|
*pdwProductType = PRODTYPE_WKSTA;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
error:
|
|
|
|
|
|
if ( hkLocalMachine )
|
|
RegCloseKey(hkLocalMachine);
|
|
|
|
if ( hkProductOptions )
|
|
RegCloseKey(hkProductOptions);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Get Sid of account name [lpszAccountName] from server [lpszServerName].
|
|
// Unmarshall the Sid into cache [pPropertyCache] if [fExplict] is TRUE.
|
|
// Use local machine if [lpszServerName] == NULL.
|
|
//
|
|
|
|
HRESULT
|
|
GetSidIntoCache(
|
|
IN LPTSTR lpszServerName,
|
|
IN LPTSTR lpszAccountName,
|
|
IN CPropertyCache * pPropertyCache,
|
|
IN BOOL fExplicit
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fGotSid = FALSE;
|
|
DWORD dwErr = 0;
|
|
PSID pSid = NULL;
|
|
DWORD dwSidLength = 0;
|
|
WCHAR szNewAccountName[MAX_PATH+UNLEN+2];
|
|
LPTSTR lpSrvName;
|
|
|
|
//
|
|
// default cbSid size :
|
|
// - 1 (revision), 1 (authid), max sub(auth)
|
|
// - * 8 (rev, authid, subid all < 8), but use 8 in case of
|
|
// structure aligment because of compiler/machine (we want
|
|
// LookUpAccountName() to succeed at first attempt as much
|
|
// as possible to min this wired call)
|
|
//
|
|
|
|
const DWORD maxSid = (1+1+SID_MAX_SUB_AUTHORITIES) * 8;
|
|
DWORD cbSid = maxSid;
|
|
|
|
//
|
|
// dummies
|
|
//
|
|
|
|
TCHAR szRefDomainName[MAX_PATH];
|
|
DWORD cbRefDomainName = MAX_PATH;
|
|
SID_NAME_USE eNameUse;
|
|
|
|
|
|
if (!lpszAccountName)
|
|
RRETURN(E_ADS_INVALID_USER_OBJECT);
|
|
|
|
if (!pPropertyCache)
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
|
|
//
|
|
// allocate sid and RefDomainName buffer
|
|
//
|
|
|
|
pSid = (PSID) AllocADsMem(
|
|
cbSid
|
|
);
|
|
if (!pSid) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// get sid and other unused info from server
|
|
//
|
|
|
|
fGotSid = LookupAccountName(
|
|
lpszServerName,
|
|
lpszAccountName,
|
|
pSid,
|
|
&cbSid,
|
|
szRefDomainName,
|
|
&cbRefDomainName,
|
|
&eNameUse
|
|
);
|
|
|
|
if (!fGotSid) {
|
|
|
|
if (cbSid>maxSid) {
|
|
|
|
//
|
|
// Fail becuase buffer size required > what we have allocated
|
|
// for some reasons, retry with correct buffer size
|
|
//
|
|
|
|
FreeADsMem(pSid);
|
|
|
|
pSid = (PSID) AllocADsMem(
|
|
cbSid
|
|
);
|
|
if (!pSid) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
fGotSid = LookupAccountName(
|
|
lpszServerName,
|
|
lpszAccountName,
|
|
pSid,
|
|
&cbSid,
|
|
szRefDomainName,
|
|
&cbRefDomainName,
|
|
&eNameUse
|
|
);
|
|
|
|
if (!fGotSid) {
|
|
|
|
//
|
|
// Fail on retry with proper buffer size, can do no more
|
|
//
|
|
|
|
dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Fail becuase of reasons other then buffer size, not need to
|
|
// retry.
|
|
//
|
|
|
|
dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
}
|
|
|
|
if( fGotSid && (eNameUse == SidTypeDomain) ) {
|
|
lpSrvName = lpszServerName;
|
|
if (lpszServerName && (lpszServerName[0] == L'\\') && (lpszServerName[1] == L'\\')) {
|
|
lpSrvName += 2;
|
|
}
|
|
|
|
#ifdef WIN95
|
|
if (!_wcsicmp(lpszAccountName, lpSrvName)) {
|
|
#else
|
|
if (CompareStringW(
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
NORM_IGNORECASE,
|
|
lpszAccountName,
|
|
-1,
|
|
lpSrvName,
|
|
-1
|
|
) == CSTR_EQUAL ) {
|
|
#endif
|
|
wcscpy(szNewAccountName, lpSrvName);
|
|
wcscat(szNewAccountName, L"\\");
|
|
wcscat(szNewAccountName, lpszAccountName);
|
|
|
|
cbSid = maxSid;
|
|
cbRefDomainName = MAX_PATH;
|
|
|
|
fGotSid = LookupAccountName(
|
|
lpszServerName,
|
|
szNewAccountName,
|
|
pSid,
|
|
&cbSid,
|
|
szRefDomainName,
|
|
&cbRefDomainName,
|
|
&eNameUse
|
|
);
|
|
|
|
if (!fGotSid) {
|
|
|
|
if (cbSid>maxSid) {
|
|
|
|
//
|
|
// Fail becuase buffer size required > what we have allocated
|
|
// for some reasons, retry with correct buffer size
|
|
//
|
|
|
|
FreeADsMem(pSid);
|
|
|
|
pSid = (PSID) AllocADsMem(
|
|
cbSid
|
|
);
|
|
if (!pSid) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
fGotSid = LookupAccountName(
|
|
lpszServerName,
|
|
szNewAccountName,
|
|
pSid,
|
|
&cbSid,
|
|
szRefDomainName,
|
|
&cbRefDomainName,
|
|
&eNameUse
|
|
);
|
|
|
|
if (!fGotSid) {
|
|
|
|
//
|
|
// Fail on retry with proper buffer size, can do no more
|
|
//
|
|
|
|
dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Fail becuase of reasons other then buffer size, not need to
|
|
// retry.
|
|
//
|
|
|
|
dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// On NT4 for some reason GetLengthSID does not set lasterror to 0
|
|
//
|
|
SetLastError(NO_ERROR);
|
|
|
|
dwSidLength = GetLengthSid((PSID) pSid);
|
|
|
|
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);
|
|
//
|
|
// store Sid in property cache
|
|
//
|
|
|
|
hr = SetOctetPropertyInCache(
|
|
pPropertyCache,
|
|
TEXT("objectSid"),
|
|
(PBYTE) pSid,
|
|
dwSidLength,
|
|
fExplicit
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
error:
|
|
|
|
if (pSid) {
|
|
FreeADsMem(pSid);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|