windows-nt/Source/XPSP1/NT/net/mmc/mprsnap/raputil.cpp
2020-09-26 16:20:57 +08:00

926 lines
24 KiB
C++

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
/**********************************************************************/
#include <stdafx.h>
#include <sdoias.h>
#include "raputil.h"
//////////
// Extract an interface pointer from a VARIANT struct.
//////////
HRESULT
GetInterfaceFromVariant(
IN VARIANT *var,
IN REFIID riid,
OUT PVOID *ppv
)
{
HRESULT hr;
// Check the parameters.
if (!var || !ppv) { return E_POINTER; }
// Switch based on the VARIANT type.
switch (V_VT(var))
{
case VT_UNKNOWN:
hr = V_UNKNOWN(var)->QueryInterface(riid, ppv);
break;
case VT_DISPATCH:
hr = V_DISPATCH(var)->QueryInterface(riid, ppv);
break;
default:
hr = DISP_E_TYPEMISMATCH;
}
return hr;
}
//////////
// Removes an integer value from a SAFEARRAY of VARIANTs.
//////////
HRESULT
RemoveIntegerFromArray(
IN VARIANT* array,
IN LONG value
)
{
VARIANT *begin, *end, *i;
// Check the parameters.
if (!array)
{
return E_POINTER;
}
else if (V_VT(array) == VT_EMPTY)
{
// If the VARIANT is empty, then the value doesn't exists, so there's
// nothing to do.
return S_OK;
}
else if (V_VT(array) != (VT_ARRAY | VT_VARIANT))
{
// The VARIANT doesn't contain a SAFEARRAY of VARIANTs.
return DISP_E_TYPEMISMATCH;
}
// Compute the beginning and end of the array data.
begin = (VARIANT*)V_ARRAY(array)->pvData;
end = begin + V_ARRAY(array)->rgsabound[0].cElements;
// Search for the value to be removed.
for (i = begin; i != end && V_I4(i) != value; ++i)
{
if (V_VT(i) == VT_I4 && V_I4(i) == value)
{
// We found a match, so remove it from the array ...
memmove(i, i + 1, ((end - i) - 1) * sizeof(VARIANT));
// ... and decrement the number of elements.
--(V_ARRAY(array)->rgsabound[0].cElements);
// We don't allow duplicates, so we're done.
break;
}
}
return S_OK;
}
//////////
// Adds an integer value to a SAFEARRAY of VARIANTs.
//////////
HRESULT
AddIntegerToArray(
IN VARIANT *array,
IN LONG value
)
{
ULONG nelem;
VARIANT *begin, *end, *i;
SAFEARRAY* psa;
// Check the parameters.
if (!array)
{
return E_POINTER;
}
else if (V_VT(array) == VT_EMPTY)
{
// The VARIANT is empty, so create a new array.
psa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (!psa) { return E_OUTOFMEMORY; }
// Set the value of the lone element.
i = (VARIANT*)psa->pvData;
V_VT(i) = VT_I4;
V_I4(i) = value;
// Store the SAFEARRAY in the VARIANT.
V_VT(array) = (VT_ARRAY | VT_VARIANT);
V_ARRAY(array) = psa;
return S_OK;
}
else if (V_VT(array) != (VT_ARRAY | VT_VARIANT))
{
// The VARIANT doesn't contain a SAFEARRAY of VARIANTs.
return DISP_E_TYPEMISMATCH;
}
// Compute the beginning and end of the array data.
nelem = V_ARRAY(array)->rgsabound[0].cElements;
begin = (VARIANT*)V_ARRAY(array)->pvData;
end = begin + nelem;
// See if the value already exists, ...
for (i = begin; i != end; ++i)
{
if (V_I4(i) == value)
{
// ... and if it does, then there's nothing to do.
return S_OK;
}
}
// Create a new array with enough room for the new element.
psa = SafeArrayCreateVector(VT_VARIANT, 0, nelem + 1);
if (!psa) { return E_OUTOFMEMORY; }
i = (VARIANT*)psa->pvData;
// Copy in the old data.
memcpy(i + 1, begin, nelem * sizeof(VARIANT));
// Add the new element.
V_VT(i) = VT_I4;
V_I4(i) = value;
// Destroy the old array ...
SafeArrayDestroy(V_ARRAY(array));
// ... and save the new one.
V_ARRAY(array) = psa;
return S_OK;
}
//////////
// Create a machine SDO and attach to the local machine.
//////////
HRESULT
OpenMachineSdo(
IN LPWSTR wszMachineName,
OUT ISdoMachine **ppMachine
)
{
HRESULT hr;
USES_CONVERSION;
// Check the parameters.
if (!ppMachine) { return E_POINTER; }
// Create the SdoMachine object.
hr = CoCreateInstance(
CLSID_SdoMachine,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISdoMachine,
(PVOID*)ppMachine
);
if (SUCCEEDED(hr))
{
// Attach to the local machine.
BSTR bstrMachineName = W2BSTR(wszMachineName);
hr = (*ppMachine)->Attach(bstrMachineName);
if (FAILED(hr))
{
// We couldn't attach, so don't return the SDO to the caller.
(*ppMachine)->Release();
ppMachine = NULL;
}
SysFreeString(bstrMachineName);
}
return hr;
}
//////////
// Given a machine SDO and a service name, retrieve the service SDO.
//////////
HRESULT
OpenServiceSDO(
IN ISdoMachine *pMachine,
IN LPWSTR wszServiceName,
OUT ISdo **ppService
)
{
HRESULT hr;
IUnknown* pUnk;
BSTR bstrServiceName = NULL;
// Create a BSTR for the service name
bstrServiceName = SysAllocString(wszServiceName);
if (bstrServiceName == NULL)
return E_OUTOFMEMORY;
// Check the parameters.
if (!pMachine || !ppService) { return E_POINTER; }
// Retrieve the service SDO ...
hr = pMachine->GetServiceSDO(
DATA_STORE_LOCAL,
bstrServiceName,
&pUnk
);
if (SUCCEEDED(hr))
{
// ... and query for the ISdo interface.
hr = pUnk->QueryInterface(IID_ISdo, (PVOID*)ppService );
pUnk->Release();
}
SysFreeString(bstrServiceName);
return hr;
}
//////////
// Given a machine SDO, retrieve the dictionary SDO.
//////////
HRESULT
OpenDictionarySDO(
IN ISdoMachine *pMachine,
OUT ISdoDictionaryOld **ppDictionary
)
{
HRESULT hr;
IUnknown* pUnk;
// Check the parameters.
if (!ppDictionary) { return E_POINTER; }
// Get the dictionary SDO ...
hr = pMachine->GetDictionarySDO(&pUnk);
if (SUCCEEDED(hr))
{
// ... and query for the ISdoDictionaryOld interface.
hr = pUnk->QueryInterface(IID_ISdoDictionaryOld,
(PVOID*)ppDictionary
);
pUnk->Release();
}
return hr;
}
//////////
// Given a parent SDO, retrieve a child SDO with the given property ID.
//////////
HRESULT
OpenChildObject(
IN ISdo *pParent,
IN LONG lProperty,
IN REFIID riid,
OUT PVOID *ppv
)
{
HRESULT hr;
VARIANT val;
// Check the parameters.
if (!pParent || !ppv) { return E_POINTER; }
// ISdo::GetProperty requires the out parameters to be initialized.
VariantInit(&val);
// Get the property corresponding to the child object ...
hr = pParent->GetProperty(
lProperty,
&val
);
if (SUCCEEDED(hr))
{
// ... and convert it to the desired interface.
hr = GetInterfaceFromVariant(
&val,
riid,
ppv
);
VariantClear(&val);
}
return hr;
}
//////////
// Given a service SDO, retrieve the default profile. If more than one profile
// exists, this function returns ERROR_NO_DEFAULT_PROFILE.
//////////
HRESULT
GetDefaultProfile(
IN ISdo* pService,
OUT ISdo** ppProfile
)
{
HRESULT hr;
ISdoCollection* pProfiles;
LONG count;
ULONG ulCount;
IUnknown* pUnk;
IEnumVARIANT* pEnum;
VARIANT val;
// Check the parameters.
if (!pService || !ppProfile) { return E_POINTER; }
// Null this out, so we can safely release it on exit.
pProfiles = NULL;
do
{
// Get the profiles collection, which is a child of the service SDO.
hr = OpenChildObject(
pService,
PROPERTY_IAS_PROFILES_COLLECTION,
IID_ISdoCollection,
(PVOID*)&pProfiles
);
if (FAILED(hr)) { break; }
// How many profiles are there?
hr = pProfiles->get_Count(
&count
);
if (FAILED(hr)) { break; }
// If there's more than one, then there's no default.
if (count != 1)
{
hr = ERROR_NO_DEFAULT_PROFILE;
break;
}
// Get an enumerator for the collection.
hr = pProfiles->get__NewEnum(
&pUnk
);
if (FAILED(hr)) { break; }
hr = pUnk->QueryInterface(
IID_IEnumVARIANT,
(PVOID*)&pEnum
);
pUnk->Release();
if (FAILED(hr)) { break; }
// Get the first (and only) object in the collection.
VariantInit(&val);
hr = pEnum->Next(
1,
&val,
&ulCount
);
if (SUCCEEDED(hr))
{
if (ulCount == 1)
{
// Get the ISdo interface for the default profile.
hr = GetInterfaceFromVariant(
&val,
IID_ISdo,
(PVOID*)ppProfile
);
VariantClear(&val);
}
else
{
// This should never happen since we already checked the count.
hr = ERROR_NO_DEFAULT_PROFILE;
}
pEnum->Release();
}
} while (FALSE);
// Release the Profiles collection.
if (pProfiles) { pProfiles->Release(); }
return hr;
}
//////////
// Get a particular attribute SDO from the collection. If the attribute doesn't
// exist and pDictionary is non-NULL, then a new attribute will be created.
//////////
HRESULT
GetAttribute(
IN ISdoCollection *pAttributes,
IN OPTIONAL ISdoDictionaryOld *pDictionary,
IN PCWSTR wszName,
OUT ISdo **ppAttribute
)
{
HRESULT hr;
VARIANT key;
IDispatch* pDisp;
ATTRIBUTEID attrId;
// Check the parameters
if (!pAttributes || !ppAttribute) { return E_POINTER; }
// Create a VARIANT key to look up the attribute.
VariantInit(&key);
V_VT(&key) = VT_BSTR;
V_BSTR(&key) = SysAllocString(wszName);
if (!V_BSTR(&key)) { return E_OUTOFMEMORY; }
// Retrieve the desired attribute.
hr = pAttributes->Item(
&key,
&pDisp
);
// If it doesn't exist and me have a dictionary, create a new attribute.
if (hr == DISP_E_MEMBERNOTFOUND && pDictionary)
{
// Look up the attribute ID.
hr = pDictionary->GetAttributeID(
V_BSTR(&key),
&attrId
);
if (SUCCEEDED(hr))
{
// Create an attribute SDO.
hr = pDictionary->CreateAttribute(
attrId,
&pDisp
);
if (SUCCEEDED(hr))
{
// Add it to the attributes collection.
hr = pAttributes->Add(
V_BSTR(&key),
&pDisp
);
if (FAILED(hr))
{
// If we couldn't add it, then release the object.
pDisp->Release();
}
}
}
}
// If we successfully retrieved or created an attribute, then get it's
// ISdo interface.
if (SUCCEEDED(hr))
{
hr = pDisp->QueryInterface(
IID_ISdo,
(PVOID*)ppAttribute
);
pDisp->Release();
}
// We're done with the key.
VariantClear(&key);
return hr;
}
//////////
// Sets/Adds a single-valued integer attribute in a profile.
//////////
HRESULT
SetIntegerAttribute(
IN ISdoCollection *pAttributes,
IN OPTIONAL ISdoDictionaryOld *pDictionary,
IN LPWSTR wszName,
IN LONG lValue
)
{
HRESULT hr;
ISdo *pAttribute;
VARIANT val;
// Get the attribute SDO.
hr = GetAttribute(
pAttributes,
pDictionary,
wszName,
&pAttribute
);
if (SUCCEEDED(hr))
{
// Initialize the attribute value ...
VariantInit(&val);
V_VT(&val) = VT_I4;
V_I4(&val) = lValue;
// ... and set the value property.
hr = pAttribute->PutProperty(
PROPERTY_ATTRIBUTE_VALUE,
&val
);
pAttribute->Release();
}
return hr;
}
HRESULT
SetBooleanAttribute (
IN ISdoCollection *pAttributes,
IN OPTIONAL ISdoDictionaryOld *pDictionary,
IN LPWSTR wszName,
IN BOOL lValue
)
{
HRESULT hr;
ISdo *pAttribute;
VARIANT val;
// Get the attribute SDO.
hr = GetAttribute(
pAttributes,
pDictionary,
wszName,
&pAttribute
);
if (SUCCEEDED(hr))
{
// Initialize the attribute value ...
VariantInit(&val);
V_VT(&val) = VT_BOOL;
V_BOOL(&val) = (VARIANT_BOOL)lValue;
// ... and set the value property.
hr = pAttribute->PutProperty(
PROPERTY_ATTRIBUTE_VALUE,
&val
);
pAttribute->Release();
}
return hr;
}
HRESULT SetDialinSetting( IN ISdoCollection *pAttributes,
IN OPTIONAL ISdoDictionaryOld *pDictionary,
BOOL fDialinAllowed)
{
long ulCount;
ULONG ulCountReceived;
HRESULT hr = S_OK;
CComBSTR bstr;
CComPtr<IUnknown> spUnknown;
CComPtr<IEnumVARIANT> spEnumVariant;
CComPtr<ISdoDictionaryOld> spDictionarySdo(pDictionary);
CComVariant var;
//
// get the attribute collection of this profile
//
CComPtr<ISdoCollection> spProfAttrCollectionSdo ( pAttributes );
// We check the count of items in our collection and don't bother getting the
// enumerator if the count is zero.
// This saves time and also helps us to a void a bug in the the enumerator which
// causes it to fail if we call next when it is empty.
hr = spProfAttrCollectionSdo->get_Count( & ulCount );
if ( FAILED(hr) )
{
return hr;
}
if ( ulCount > 0)
{
// Get the enumerator for the attribute collection.
hr = spProfAttrCollectionSdo->get__NewEnum( (IUnknown **) & spUnknown );
if ( FAILED(hr) )
{
return hr;
}
hr = spUnknown->QueryInterface( IID_IEnumVARIANT, (void **) &spEnumVariant );
spUnknown.Release();
if ( FAILED(hr) )
{
return hr;
}
// Get the first item.
hr = spEnumVariant->Next( 1, &var, &ulCountReceived );
while( SUCCEEDED( hr ) && ulCountReceived == 1 )
{
// Get an sdo pointer from the variant we received.
CComPtr<ISdo> spSdo;
hr = V_DISPATCH(&var)->QueryInterface( IID_ISdo, (void **) &spSdo );
if ( !SUCCEEDED(hr))
{
return hr;
}
//
// get attribute ID
//
var.Clear();
hr = spSdo->GetProperty(PROPERTY_ATTRIBUTE_ID, &var);
if ( !SUCCEEDED(hr) )
{
return hr;
}
DWORD dwAttrId = V_I4(&var);
if ( dwAttrId == (DWORD)IAS_ATTRIBUTE_ALLOW_DIALIN )
{
// found this one in the profile, check for its value
var.Clear();
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = fDialinAllowed ? VARIANT_TRUE: VARIANT_FALSE ;
hr = spSdo->PutProperty(PROPERTY_ATTRIBUTE_VALUE, &var);
if ( !SUCCEEDED(hr) )
{
return hr;
}
return S_OK;
}
// Clear the variant of whatever it had --
// this will release any data associated with it.
var.Clear();
// Get the next item.
hr = spEnumVariant->Next( 1, &var, &ulCountReceived );
if ( !SUCCEEDED(hr))
{
return hr;
}
} // while
} // if
// if we reach here, it means we either haven't found the attribute,
// or the profile doesn't have anything in its attribute collection.
if ( !fDialinAllowed )
{
// we don't need to do anything if dialin is allowed, becuase if this
// attribute is not in the profile, then dialin is by default allowed
// but we need to add this attribute to the profile if it's DENIED
// create the SDO for this attribute
CComPtr<IDispatch> spDispatch;
hr = spDictionarySdo->CreateAttribute( (ATTRIBUTEID)IAS_ATTRIBUTE_ALLOW_DIALIN,
(IDispatch**)&spDispatch.p);
if ( !SUCCEEDED(hr) )
{
return hr;
}
// add this node to profile attribute collection
hr = spProfAttrCollectionSdo->Add(NULL, (IDispatch**)&spDispatch.p);
if ( !SUCCEEDED(hr) )
{
return hr;
}
//
// get the ISdo pointer
//
CComPtr<ISdo> spAttrSdo;
hr = spDispatch->QueryInterface( IID_ISdo, (void **) &spAttrSdo);
if ( !SUCCEEDED(hr) )
{
return hr;
}
// set sdo property for this attribute
CComVariant var;
// set value
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = VARIANT_FALSE;
hr = spAttrSdo->PutProperty(PROPERTY_ATTRIBUTE_VALUE, &var);
if ( !SUCCEEDED(hr) )
{
return hr;
}
var.Clear();
} // if (!dialinallowed)
return hr;
}
//////////
// Update the default policy based on the specified flags.
//////////
HRESULT
UpdateDefaultPolicy(
IN LPWSTR wszMachineName,
IN BOOL fEnableMSCHAPv1,
IN BOOL fEnableMSCHAPv2,
IN BOOL fRequireEncryption
)
{
HRESULT hr;
ISdoMachine *pMachine;
ISdo *pService, *pProfile, *pAuthType;
ISdoDictionaryOld *pDictionary;
ISdoCollection *pAttributes;
VARIANT val;
// Initialize the local variables, so we can safely clean up on exit.
pMachine = NULL;
pService = pProfile = pAuthType = NULL;
pDictionary = NULL;
pAttributes = NULL;
VariantInit(&val);
do
{
hr = OpenMachineSdo(wszMachineName, &pMachine);
if (FAILED(hr)) { break; }
hr = OpenServiceSDO(pMachine, L"RemoteAccess", &pService);
if (FAILED(hr)) { break; }
hr = OpenDictionarySDO(pMachine, &pDictionary);
if (FAILED(hr)) { break; }
hr = GetDefaultProfile(pService, &pProfile);
if (FAILED(hr)) { break; }
// Get the attributes collection, which is a child of the profile.
hr = OpenChildObject(
pProfile,
PROPERTY_PROFILE_ATTRIBUTES_COLLECTION,
IID_ISdoCollection,
(PVOID*)&pAttributes
);
if (FAILED(hr)) { break; }
// Get the current value of the NP-Authentication-Type attribute.
hr = GetAttribute(
pAttributes,
pDictionary,
L"NP-Authentication-Type",
&pAuthType
);
if (FAILED(hr)) { break; }
hr = pAuthType->GetProperty(
PROPERTY_ATTRIBUTE_VALUE,
&val
);
if (FAILED(hr)) { break; }
// Update MS-CHAP v1
if (fEnableMSCHAPv1)
{
hr = AddIntegerToArray(&val, 3);
}
else
{
hr = RemoveIntegerFromArray(&val, 3);
}
if (FAILED(hr)) { break; }
// Update MS-CHAP v2
if (fEnableMSCHAPv2)
{
hr = AddIntegerToArray(&val, 4);
}
else
{
hr = RemoveIntegerFromArray(&val, 4);
}
if (FAILED(hr)) { break; }
// Write the new value back to the attribute.
hr = pAuthType->PutProperty(
PROPERTY_ATTRIBUTE_VALUE,
&val
);
if (FAILED(hr)) { break; }
// Update the encryption attributes if necessary.
if (fRequireEncryption)
{
hr = SetIntegerAttribute(
pAttributes,
pDictionary,
L"MS-MPPE-Encryption-Policy",
2
);
if (FAILED(hr)) { break; }
hr = SetIntegerAttribute(
pAttributes,
pDictionary,
L"MS-MPPE-Encryption-Types",
14
);
if (FAILED(hr)) { break; }
}
//
//Update the default for msNPAllowDialin - This should be set
//to deny permissions by default
//
hr = SetDialinSetting(pAttributes,pDictionary, FALSE);
if (FAILED(hr)) { break; }
hr = pProfile->Apply();
} while (FALSE);
// Clean up.
VariantClear(&val);
if (pAttributes)
pAttributes->Release();
if (pDictionary)
pDictionary->Release();
if (pAuthType)
pAuthType->Release();
if (pProfile)
pProfile->Release();
if (pService)
pService->Release();
if (pMachine)
pMachine->Release();
return hr;
}
#if 0
#include <stdio.h>
int __cdecl wmain(int argc, wchar_t *argv[])
{
HRESULT hr;
BOOL fEnableMSCHAPv1, fEnableMSCHAPv2, fRequireEncryption;
if (argc != 4)
{
wprintf(L"Usage: wizard <t|f> <t|f> <t|f>\n"
L" 1st flag: MS-CHAP v1 enabled\n"
L" 2nd flag: MS-CHAP v2 enabled\n"
L" 3rd flag: Encryption required\n");
return -1;
}
fEnableMSCHAPv1 = argv[1][0] == 't' ? TRUE : FALSE;
fEnableMSCHAPv2 = argv[2][0] == 't' ? TRUE : FALSE;
fRequireEncryption = argv[3][0] == 't' ? TRUE : FALSE;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = UpdateDefaultPolicy(
NULL, // Machine name.
fEnableMSCHAPv1,
fEnableMSCHAPv2,
fRequireEncryption
);
if (SUCCEEDED(hr))
{
wprintf(L"UpdateDefaultPolicy succeeded.\n");
}
else
{
wprintf(L"UpdateDefaultPolicy returned: 0x%08X.\n", hr);
}
CoUninitialize();
return 0;
}
#endif