/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/ #include #include #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 spUnknown; CComPtr spEnumVariant; CComPtr spDictionarySdo(pDictionary); CComVariant var; // // get the attribute collection of this profile // CComPtr 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 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 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 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 int __cdecl wmain(int argc, wchar_t *argv[]) { HRESULT hr; BOOL fEnableMSCHAPv1, fEnableMSCHAPv2, fRequireEncryption; if (argc != 4) { wprintf(L"Usage: wizard \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