#include "pch.h" #pragma hdrstop #include "nccom.h" #include "ncnetcon.h" #include "ncreg.h" #include "saconob.h" static const CLSID CLSID_SharedAccessConnectionUi = {0x7007ACD5,0x3202,0x11D1,{0xAA,0xD2,0x00,0x80,0x5F,0xC1,0x27,0x0E}}; static const WCHAR c_szConnName[] = L"Name"; static const WCHAR c_szShowIcon[] = L"ShowIcon"; static const WCHAR c_szSharedAccessClientKeyPath[] = L"System\\CurrentControlSet\\Control\\Network\\SharedAccessConnection"; #define UPNP_ACTION_HRESULT(lError) (UPNP_E_ACTION_SPECIFIC_BASE + (lError - FAULT_ACTION_SPECIFIC_BASE)) CSharedAccessConnection::CSharedAccessConnection() { m_pSharedAccessBeacon = NULL; m_pWANConnectionService = NULL; } HRESULT CSharedAccessConnection::FinalConstruct() { HRESULT hr = S_OK; ISharedAccessBeaconFinder* pBeaconFinder; hr = HrCreateInstance(CLSID_SharedAccessConnectionManager, CLSCTX_SERVER, &pBeaconFinder); if(SUCCEEDED(hr)) { hr = pBeaconFinder->GetSharedAccessBeacon(NULL, &m_pSharedAccessBeacon); if(SUCCEEDED(hr)) { NETCON_MEDIATYPE MediaType; hr = m_pSharedAccessBeacon->GetMediaType(&MediaType); if(SUCCEEDED(hr)) { hr = m_pSharedAccessBeacon->GetService(NCM_SHAREDACCESSHOST_LAN == MediaType ? SAHOST_SERVICE_WANIPCONNECTION : SAHOST_SERVICE_WANPPPCONNECTION, &m_pWANConnectionService); } } pBeaconFinder->Release(); } return hr; } HRESULT CSharedAccessConnection::FinalRelease() { HRESULT hr = S_OK; if(NULL != m_pSharedAccessBeacon) { m_pSharedAccessBeacon->Release(); } if(NULL != m_pWANConnectionService) { m_pWANConnectionService->Release(); } return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::GetConnectionName // // Purpose: Initializes the connection object for the first time. // // Arguments: // (none) // // Returns: S_OK if success, Win32 or OLE error code otherwise // // Author: kenwic 8 Aug 2000 // // Notes: This function is only called when the object is created for // the very first time and has no identity. // HRESULT CSharedAccessConnection::GetConnectionName(LPWSTR* pName) { HRESULT hr = S_OK; HKEY hKey; // first get the user assigned name hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szSharedAccessClientKeyPath, KEY_READ, &hKey); if(SUCCEEDED(hr)) { tstring strName; hr = HrRegQueryString(hKey, c_szConnName, &strName); if (SUCCEEDED(hr)) { hr = HrCoTaskMemAllocAndDupSz (strName.c_str(), pName, NETCON_MAX_NAME_LEN); } RegCloseKey(hKey); } // if that doesn't exist, construct the name if(FAILED(hr)) { IUPnPService* pOSInfoService; hr = m_pSharedAccessBeacon->GetService(SAHOST_SERVICE_OSINFO, &pOSInfoService); if(SUCCEEDED(hr)) { BSTR MachineName; hr = GetStringStateVariable(pOSInfoService, L"OSMachineName", &MachineName); if(SUCCEEDED(hr)) { BSTR SharedAdapterName; hr = GetStringStateVariable(m_pWANConnectionService, L"X_Name", &SharedAdapterName); if(SUCCEEDED(hr)) { LPWSTR szNameString; LPCWSTR szTemplateString = SzLoadIds(IDS_SHAREDACCESS_CONN_NAME); Assert(NULL != szTemplateString); LPOLESTR pszParams[] = {SharedAdapterName, MachineName}; if(0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, szTemplateString, 0, 0, reinterpret_cast(&szNameString), 0, reinterpret_cast(pszParams))) { HrCoTaskMemAllocAndDupSz (szNameString, pName, NETCON_MAX_NAME_LEN); LocalFree(szNameString); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } SysFreeString(SharedAdapterName); } SysFreeString(MachineName); } pOSInfoService->Release(); } } // if that fails, use the default if(FAILED(hr)) { hr = HrCoTaskMemAllocAndDupSz (SzLoadIds(IDS_SHAREDACCESS_DEFAULT_CONN_NAME), pName, NETCON_MAX_NAME_LEN); } TraceError("CSharedAccessConnection::HrInitialize", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::GetStatus // // Purpose: Returns the status of this ICS connection // // Arguments: // pStatus [out] Returns status value // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: kenwic 8 Aug 2000 // // Notes: // HRESULT CSharedAccessConnection::GetStatus(NETCON_STATUS *pStatus) { HRESULT hr = S_OK; if (!pStatus) { hr = E_POINTER; } else { BSTR ConnectionStatus; hr = GetStringStateVariable(m_pWANConnectionService, L"ConnectionStatus", &ConnectionStatus); if(SUCCEEDED(hr)) { if(0 == lstrcmp(ConnectionStatus, L"Connected")) { *pStatus = NCS_CONNECTED; } else if(0 == lstrcmp(ConnectionStatus, L"Disconnected")) { *pStatus = NCS_DISCONNECTED; } else if(0 == lstrcmp(ConnectionStatus, L"Unconfigured")) { *pStatus = NCS_HARDWARE_DISABLED; // REVIEW: better state? } else if(0 == lstrcmp(ConnectionStatus, L"Connecting")) { *pStatus = NCS_CONNECTING; } else if(0 == lstrcmp(ConnectionStatus, L"Authenticating")) { *pStatus = NCS_CONNECTING; } else if(0 == lstrcmp(ConnectionStatus, L"PendingDisconnect")) { *pStatus = NCS_DISCONNECTING; } else if(0 == lstrcmp(ConnectionStatus, L"Disconnecting")) { *pStatus = NCS_DISCONNECTING; } else { *pStatus = NCS_HARDWARE_DISABLED; } SysFreeString(ConnectionStatus); } } TraceError("CSharedAccessConnection::GetStatus", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::GetCharacteristics // // Purpose: Returns the characteristics of this connection type // // Arguments: // pdwFlags [out] Returns characteristics flags // // Returns: S_OK if successful, OLE or Win32 error code otherwise // // Author: kenwic 8 Aug 2000 // // Notes: // HRESULT CSharedAccessConnection::GetCharacteristics(DWORD* pdwFlags) { Assert (pdwFlags); // TODO when get have a place to save the name, allow rename HRESULT hr = S_OK; *pdwFlags = NCCF_ALL_USERS | NCCF_ALLOW_RENAME; // REVIEW always ok, group policy? HKEY hKey; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szSharedAccessClientKeyPath, KEY_QUERY_VALUE, &hKey); if(SUCCEEDED(hr)) { DWORD dwShowIcon = 0; DWORD dwSize = sizeof(dwShowIcon); DWORD dwType; hr = HrRegQueryValueEx(hKey, c_szShowIcon, &dwType, reinterpret_cast(&dwShowIcon), &dwSize); if(SUCCEEDED(hr) && REG_DWORD == dwType) { if(0 != dwShowIcon) { *pdwFlags |= NCCF_SHOW_ICON; } } RegCloseKey(hKey); } hr = S_OK; // it's ok if the key doesn't exist TraceError("CSharedAccessConnection::GetCharacteristics", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::Connect // // Purpose: Connects the remote ICS host // // Arguments: // (none) // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: kenwic 8 Aug 2000 // HRESULT CSharedAccessConnection::Connect() { HRESULT hr = S_OK; VARIANT OutArgs; hr = InvokeVoidAction(m_pWANConnectionService, L"RequestConnection", &OutArgs); if(UPNP_ACTION_HRESULT(800) == hr) { hr = E_ACCESSDENIED; VariantClear(&OutArgs); } TraceError("CSharedAccessConnection::Connect", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::Disconnect // // Purpose: Disconnects the remote ICS host // // Arguments: // (none) // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: kenwic 8 Aug 2000 // HRESULT CSharedAccessConnection::Disconnect() { HRESULT hr = S_OK; VARIANT OutArgs; hr = InvokeVoidAction(m_pWANConnectionService, L"ForceTermination", &OutArgs); if(UPNP_ACTION_HRESULT(800) == hr) { hr = E_ACCESSDENIED; VariantClear(&OutArgs); } TraceError("CSharedAccessConnection::Disconnect", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::Delete // // Purpose: Delete the remote ICS connection. This not allowed. // // Arguments: // (none) // // Returns: E_FAIL; // // Author: kenwic 8 Aug 2000 // // Notes: This function is not expected to ever be called. // HRESULT CSharedAccessConnection::Delete() { return E_FAIL; // can't delete the beacon } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::Duplicate // // Purpose: Duplicates the remote ICS connection. This not allowed. // // Arguments: // (none) // // Returns: E_UNEXPECTED; // // Author: kenwic 8 Aug 2000 // // Notes: This function is not expected to ever be called. // STDMETHODIMP CSharedAccessConnection::Duplicate ( PCWSTR pszDuplicateName, INetConnection** ppCon) { return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::GetProperties // // Purpose: Get all of the properties associated with the connection. // Returning all of them at once saves us RPCs vs. returning // each one individually. // // Arguments: // ppProps [out] Returned block of properties. // // Returns: S_OK or an error. // // Author: kenwic 8 Aug 2000 // // Notes: // STDMETHODIMP CSharedAccessConnection::GetProperties ( NETCON_PROPERTIES** ppProps) { HRESULT hr = S_OK; // Validate parameters. // if (!ppProps) { hr = E_POINTER; } else { // Initialize the output parameter. // *ppProps = NULL; NETCON_PROPERTIES* pProps; hr = HrCoTaskMemAlloc (sizeof (NETCON_PROPERTIES), reinterpret_cast(&pProps)); if (SUCCEEDED(hr)) { HRESULT hrT; ZeroMemory (pProps, sizeof (NETCON_PROPERTIES)); // guidId // pProps->guidId = CLSID_SharedAccessConnection; // there is only ever one beacon icon, so we'll just use our class id. // we can't use all zeroes because the add connection wizard does that // pszwName // hrT = GetConnectionName(&pProps->pszwName); if (FAILED(hrT)) { hr = hrT; } // pszwDeviceName // hrT = HrCoTaskMemAllocAndDupSz (pProps->pszwName, &pProps->pszwDeviceName, NETCON_MAX_NAME_LEN); // TODO the spec says the same as pszwName here, is that right if (FAILED(hrT)) { hr = hrT; } // Status // hrT = GetStatus (&pProps->Status); if (FAILED(hrT)) { hr = hrT; } if(NULL != m_pSharedAccessBeacon) { hr = m_pSharedAccessBeacon->GetMediaType(&pProps->MediaType); } else { hr = E_UNEXPECTED; } hrT = GetCharacteristics (&pProps->dwCharacter); if (FAILED(hrT)) { hr = hrT; } // clsidThisObject // pProps->clsidThisObject = CLSID_SharedAccessConnection; // clsidUiObject // pProps->clsidUiObject = CLSID_SharedAccessConnectionUi; // Assign the output parameter or cleanup if we had any failures. // if (SUCCEEDED(hr)) { *ppProps = pProps; } else { Assert (NULL == *ppProps); FreeNetconProperties (pProps); } } } TraceError ("CLanConnection::GetProperties", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::GetUiObjectClassId // // Purpose: Returns the CLSID of the object that handles UI for this // connection type // // Arguments: // pclsid [out] Returns CLSID of UI object // // Returns: S_OK if success, OLE error code otherwise // // Author: kenwic 8 Aug 2000 // // Notes: // STDMETHODIMP CSharedAccessConnection::GetUiObjectClassId(CLSID *pclsid) { HRESULT hr = S_OK; // Validate parameters. // if (!pclsid) { hr = E_POINTER; } else { *pclsid = CLSID_SharedAccessConnectionUi; } TraceError("CLanConnection::GetUiObjectClassId", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::Rename // // Purpose: Changes the name of the connection // // Arguments: // pszName [in] New connection name (must be valid) // // Returns: S_OK if success, OLE error code otherwise // // Author: kenwic 8 Aug 2000 // // Notes: // STDMETHODIMP CSharedAccessConnection::Rename(PCWSTR pszName) { HRESULT hr = S_OK; if (!pszName) { hr = E_POINTER; } else if (!FIsValidConnectionName(pszName)) { // Bad connection name hr = E_INVALIDARG; } else { HKEY hKey; hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szSharedAccessClientKeyPath, NULL, KEY_SET_VALUE, NULL, &hKey, NULL); if(SUCCEEDED(hr)) { hr = HrRegSetSz(hKey, c_szConnName, pszName); if (S_OK == hr) { INetConnectionRefresh* pNetConnectionRefresh; hr = CoCreateInstance(CLSID_ConnectionManager, NULL, CLSCTX_SERVER, IID_INetConnectionRefresh, reinterpret_cast(&pNetConnectionRefresh)); if(SUCCEEDED(hr)) { pNetConnectionRefresh->ConnectionRenamed(this); pNetConnectionRefresh->Release(); } } } } TraceError("CLanConnection::Rename", hr); return hr; } //+--------------------------------------------------------------------------- // IPersistNetConnection // //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::GetClassID // // Purpose: Returns the CLSID of connection objects // // Arguments: // pclsid [out] Returns CLSID to caller // // Returns: S_OK if success, OLE error otherwise // // Author: kenwic 8 Aug 2000 // // Notes: // STDMETHODIMP CSharedAccessConnection::GetClassID(CLSID* pclsid) { HRESULT hr = S_OK; // Validate parameters. // if (!pclsid) { hr = E_POINTER; } else { *pclsid = CLSID_SharedAccessConnection; // we just use our guid since there is only ever one saconob } TraceError("CSharedAccessConnection::GetClassID", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::GetSizeMax // // Purpose: Returns the maximum size of the persistence data // // Arguments: // pcbSize [out] Returns size // // Returns: S_OK if success, OLE error otherwise // // Author: kenwic 8 Aug 2000 // // Notes: // STDMETHODIMP CSharedAccessConnection::GetSizeMax(ULONG *pcbSize) { HRESULT hr = S_OK; // Validate parameters. // if (!pcbSize) { hr = E_POINTER; } else { *pcbSize = sizeof(GUID); } TraceError("CLanConnection::GetSizeMax", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::Load // // Purpose: Allows the connection object to initialize (restore) itself // from previously persisted data // // Arguments: // pbBuf [in] Private data to use for restoring // cbSize [in] Size of data // // Returns: S_OK if success, OLE error otherwise // // Author: kenwic 8 Aug 2000 // // Notes: // STDMETHODIMP CSharedAccessConnection::Load(const BYTE *pbBuf, ULONG cbSize) { HRESULT hr = E_INVALIDARG; // Validate parameters. // if (!pbBuf) { hr = E_POINTER; } else if (cbSize != sizeof(GUID)) { hr = E_INVALIDARG; } else { hr = S_OK; // we don't need this guid, but we have to implemenet IPersistNetConnection } TraceError("CLanConnection::Load", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::Save // // Purpose: Provides the caller with data to use in restoring this object // at a later time. // // Arguments: // pbBuf [out] Returns data to use for restoring // cbSize [in] Size of data buffer // // Returns: S_OK if success, OLE error otherwise // // Author: kenwic 8 Aug 2000 // // Notes: // STDMETHODIMP CSharedAccessConnection::Save(BYTE *pbBuf, ULONG cbSize) { HRESULT hr; // Validate parameters. // if (!pbBuf) { hr = E_POINTER; } else { CopyMemory(pbBuf, &CLSID_SharedAccessConnection, cbSize); // REVIEW can we eliminate this? } TraceError("CLanConnection::Save", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::GetInfo // // Purpose: Returns information about this connection // // Arguments: // dwMask [in] Flags that control which fields to return. Use // SACIF_ALL to get all fields. // pLanConInfo [out] Structure that holds returned information // // Returns: S_OK if success, OLE error code otherwise // // Author: kenwic 6 Sep 2000 // // Notes: Caller should delete the szwConnName value. // STDMETHODIMP CSharedAccessConnection::GetInfo(DWORD dwMask, SHAREDACCESSCON_INFO* pConInfo) { HRESULT hr = S_OK; if (!pConInfo) { hr = E_POINTER; } else { ZeroMemory(pConInfo, sizeof(SHAREDACCESSCON_INFO)); if (dwMask & SACIF_ICON) { if (SUCCEEDED(hr)) { DWORD dwValue; // OK if value not there. Default to FALSE always. // HKEY hKey; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szSharedAccessClientKeyPath, KEY_QUERY_VALUE, &hKey); if(SUCCEEDED(hr)) { if (S_OK == HrRegQueryDword(hKey, c_szShowIcon, &dwValue)) { pConInfo->fShowIcon = !!(dwValue); } RegCloseKey(hKey); } } } } // Mask S_FALSE if it slipped thru. if (S_FALSE == hr) { hr = S_OK; } TraceError("CSharedAccessConnection::GetInfo", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CSharedAccessConnection::SetInfo // // Purpose: Sets information about this connection. // // Arguments: // dwMask [in] Flags that control which fields to set // pConInfo [in] Structure containing information to set // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: kenwic 6 Sep 2000 // STDMETHODIMP CSharedAccessConnection::SetInfo(DWORD dwMask, const SHAREDACCESSCON_INFO* pConInfo) { HRESULT hr = S_OK; if (!pConInfo) { hr = E_POINTER; } else { if (dwMask & SACIF_ICON) { if (SUCCEEDED(hr)) { // Set ShowIcon value HKEY hKey; hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szSharedAccessClientKeyPath, NULL, KEY_SET_VALUE, NULL, &hKey, NULL); if(SUCCEEDED(hr)) { hr = HrRegSetDword(hKey, c_szShowIcon, pConInfo->fShowIcon); RegCloseKey(hKey); } } } if (SUCCEEDED(hr)) { INetConnectionRefresh* pNetConnectionRefresh; hr = CoCreateInstance(CLSID_ConnectionManager, NULL, CLSCTX_SERVER, IID_INetConnectionRefresh, reinterpret_cast(&pNetConnectionRefresh)); if(SUCCEEDED(hr)) { pNetConnectionRefresh->ConnectionModified(this); pNetConnectionRefresh->Release(); } } } TraceError("CSharedAccessConnection::SetInfo", hr); return hr; } HRESULT CSharedAccessConnection::GetLocalAdapterGUID(GUID* pGuid) { return m_pSharedAccessBeacon->GetLocalAdapterGUID(pGuid); } HRESULT CSharedAccessConnection::GetService(SAHOST_SERVICES ulService, IUPnPService** ppService) { return m_pSharedAccessBeacon->GetService(ulService, ppService); } HRESULT CSharedAccessConnection::GetStringStateVariable(IUPnPService* pService, LPWSTR pszVariableName, BSTR* pString) { HRESULT hr = S_OK; VARIANT Variant; VariantInit(&Variant); BSTR VariableName; VariableName = SysAllocString(pszVariableName); if(NULL != VariableName) { hr = pService->QueryStateVariable(VariableName, &Variant); if(SUCCEEDED(hr)) { if(V_VT(&Variant) == VT_BSTR) { *pString = V_BSTR(&Variant); } else { hr = E_UNEXPECTED; } } if(FAILED(hr)) { VariantClear(&Variant); } SysFreeString(VariableName); } else { hr = E_OUTOFMEMORY; } TraceHr (ttidError, FAL, hr, FALSE, "CSharedAccessConnection::GetStringStateVariable"); return hr; } HRESULT InvokeVoidAction(IUPnPService * pService, LPTSTR pszCommand, VARIANT* pOutParams) { HRESULT hr; BSTR bstrActionName; bstrActionName = SysAllocString(pszCommand); if (NULL != bstrActionName) { SAFEARRAYBOUND rgsaBound[1]; SAFEARRAY * psa = NULL; rgsaBound[0].lLbound = 0; rgsaBound[0].cElements = 0; psa = SafeArrayCreate(VT_VARIANT, 1, rgsaBound); if (psa) { LONG lStatus; VARIANT varInArgs; VARIANT varReturnVal; VariantInit(&varInArgs); VariantInit(pOutParams); VariantInit(&varReturnVal); varInArgs.vt = VT_VARIANT | VT_ARRAY; V_ARRAY(&varInArgs) = psa; hr = pService->InvokeAction(bstrActionName, varInArgs, pOutParams, &varReturnVal); if(SUCCEEDED(hr)) { VariantClear(&varReturnVal); } SafeArrayDestroy(psa); } else { hr = E_OUTOFMEMORY; } SysFreeString(bstrActionName); } else { hr = E_OUTOFMEMORY; } return hr; }