//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997 - 2001. // // File: I N B O U N D . C P P // // Contents: Implements the inbound connection object. // // Notes: // // Author: shaunco 12 Nov 1997 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "inbound.h" #include "nccom.h" #include "ncnetcon.h" #include "..\conman\conman.h" LONG g_CountIncomingConnectionObjects; static const CLSID CLSID_InboundConnectionUi = {0x7007ACC3,0x3202,0x11D1,{0xAA,0xD2,0x00,0x80,0x5F,0xC1,0x27,0x0E}}; extern const GUID GUID_InboundConfigConnectionId = { /* 89150b9f-9b5c-11d1-a91f-00805fc1270e */ 0x89150b9f, 0x9b5c, 0x11d1, {0xa9, 0x1f, 0x00, 0x80, 0x5f, 0xc1, 0x27, 0x0e} }; //+--------------------------------------------------------------------------- // // Member: CInboundConnection::CreateInstance // // Purpose: Creates an inbound connection object. // // Arguments: // fIsConfigConnection [in] // hRasSrvConn [in] // pszwName [in] // pguidId [in] // riid [in] // ppv [in] // // Returns: S_OK or an error code. // // Author: shaunco 12 Nov 1997 // // Notes: // HRESULT CInboundConnection::CreateInstance ( IN BOOL fIsConfigConnection, IN HRASSRVCONN hRasSrvConn, IN PCWSTR pszwName, IN PCWSTR pszwDeviceName, IN DWORD dwType, IN const GUID* pguidId, IN REFIID riid, OUT void** ppv) { Assert (FIff(fIsConfigConnection, !hRasSrvConn)); Assert (pguidId); HRESULT hr = E_OUTOFMEMORY; CInboundConnection* pObj; pObj = new CComObject ; if (pObj) { if (fIsConfigConnection) { // No need to start the service (FALSE) since we're being // created as a result of the service running. // pObj->InitializeAsConfigConnection (FALSE); } else { // Initialize our members. // pObj->m_fIsConfigConnection = FALSE; pObj->m_hRasSrvConn = hRasSrvConn; pObj->SetName (pszwName); pObj->SetDeviceName (pszwDeviceName); switch (dwType) { case RASSRVUI_MODEM: pObj->m_MediaType = NCM_PHONE; break; case RASSRVUI_VPN: pObj->m_MediaType = NCM_TUNNEL; break; case RASSRVUI_DCC: pObj->m_MediaType = NCM_DIRECT; break; default: pObj->m_MediaType = NCM_PHONE; break; } pObj->m_guidId = *pguidId; // We are now a full-fledged object. // pObj->m_fInitialized = TRUE; } // Do the standard CComCreator::CreateInstance stuff. // pObj->SetVoid (NULL); pObj->InternalFinalConstructAddRef (); hr = pObj->FinalConstruct (); pObj->InternalFinalConstructRelease (); if (SUCCEEDED(hr)) { INetConnection* pCon = static_cast(pObj); hr = pCon->QueryInterface (riid, ppv); } if (FAILED(hr)) { delete pObj; } } TraceError ("CInboundConnection::CreateInstance", hr); return hr; } CInboundConnection::CInboundConnection() throw() { InterlockedIncrement (&g_CountIncomingConnectionObjects); m_fIsConfigConnection = FALSE; m_hRasSrvConn = NULL; m_MediaType = NCM_NONE; m_fInitialized = FALSE; } CInboundConnection::~CInboundConnection() throw() { InterlockedDecrement (&g_CountIncomingConnectionObjects); } HRESULT CInboundConnection::GetCharacteristics ( OUT DWORD* pdwFlags) { HRESULT hr = S_OK; // Validate parameters. // if (!pdwFlags) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { *pdwFlags = NCCF_INCOMING_ONLY | NCCF_ALL_USERS; // For the configuration connection, we only allow removal. // Don't query for NCCF_SHOW_ICON (below) because this connection // never get's connected. // if (m_fIsConfigConnection) { *pdwFlags |= NCCF_ALLOW_REMOVAL; } else { BOOL fShowIcon; DWORD dwErr = RasSrvQueryShowIcon (&fShowIcon); TraceError ("RasSrvQueryShowIcon", HRESULT_FROM_WIN32(dwErr)); if ((ERROR_SUCCESS == dwErr) && fShowIcon) { *pdwFlags |= NCCF_SHOW_ICON; } } } TraceError ("CInboundConnection::GetCharacteristics", hr); return hr; } HRESULT CInboundConnection::GetStatus ( OUT NETCON_STATUS* pStatus) { Assert (pStatus); HRESULT hr = S_OK; // Initialize the output parameter. // *pStatus = NCS_DISCONNECTED; if (!m_fIsConfigConnection) { BOOL fConnected; DWORD dwErr = RasSrvIsConnectionConnected (m_hRasSrvConn, &fConnected); TraceError ("RasSrvIsConnectionConnected", HRESULT_FROM_WIN32(dwErr)); if ((ERROR_SUCCESS == dwErr) && fConnected) { *pStatus = NCS_CONNECTED; } } TraceError ("CInboundConnection::GetStatus", hr); return hr; } //+--------------------------------------------------------------------------- // INetConnection // STDMETHODIMP CInboundConnection::Connect () { return E_NOTIMPL; } STDMETHODIMP CInboundConnection::Disconnect () { HRESULT hr; // We don't expect to be called on Disconnect if we are the // configuration connection object. Why? Because this object never // reports itself as connected through GetStatus. // if (!m_fInitialized || m_fIsConfigConnection) { hr = E_UNEXPECTED; } else { DWORD dwErr = RasSrvHangupConnection (m_hRasSrvConn); hr = HRESULT_FROM_WIN32 (dwErr); TraceError ("RasSrvHangupConnection", hr); // Disconnect means this object is no longer valid. // Indicate so by uniniatializing ourselves (so subsequent // method calls will fail) and returning S_OBJECT_NO_LONGER_VALID. // m_fInitialized = FALSE; hr = S_OBJECT_NO_LONGER_VALID; } TraceError ("CInboundConnection::Disconnect", (S_OBJECT_NO_LONGER_VALID == hr) ? S_OK : hr); return hr; } STDMETHODIMP CInboundConnection::Delete () { HRESULT hr; // We don't expect to be called on Remove if we are not the // configuration connection object. Why? Because connected objects never // report themselves as removeable through GetCharacteristics. // if (!m_fInitialized || !m_fIsConfigConnection) { hr = E_UNEXPECTED; } else { DWORD dwErr = RasSrvCleanupService (); hr = HRESULT_FROM_WIN32 (dwErr); TraceError ("RasSrvCleanupService", hr); } TraceError ("CInboundConnection::Delete", hr); return hr; } STDMETHODIMP CInboundConnection::Duplicate ( IN PCWSTR pszwDuplicateName, OUT INetConnection** ppCon) { return E_NOTIMPL; } STDMETHODIMP CInboundConnection::GetProperties ( OUT NETCON_PROPERTIES** ppProps) { HRESULT hr = S_OK; // Validate parameters. // if (!ppProps) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } 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 = m_guidId; // pszwName // hrT = HrCoTaskMemAllocAndDupSz (PszwName(), &pProps->pszwName, NETCON_MAX_NAME_LEN); if (FAILED(hrT)) { hr = hrT; } // pszwDeviceName // if (!m_fIsConfigConnection) { hrT = HrCoTaskMemAllocAndDupSz (PszwDeviceName(), &pProps->pszwDeviceName, NETCON_MAX_NAME_LEN); if (FAILED(hrT)) { hr = hrT; } } // Status // hrT = GetStatus (&pProps->Status); if (FAILED(hrT)) { hr = hrT; } // MediaType // pProps->MediaType = m_MediaType; // dwCharacter // hrT = GetCharacteristics (&pProps->dwCharacter); if (FAILED(hrT)) { hr = hrT; } // clsidThisObject // pProps->clsidThisObject = CLSID_InboundConnection; // clsidUiObject // pProps->clsidUiObject = CLSID_InboundConnectionUi; // Assign the output parameter or cleanup if we had any failures. // if (SUCCEEDED(hr)) { *ppProps = pProps; } else { Assert (NULL == *ppProps); FreeNetconProperties (pProps); } } } TraceError ("CInboundConnection::GetProperties", hr); return hr; } STDMETHODIMP CInboundConnection::GetUiObjectClassId ( OUT CLSID* pclsid) { HRESULT hr = S_OK; // Validate parameters. // if (!pclsid) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { *pclsid = CLSID_InboundConnectionUi; } TraceError ("CInboundConnection::GetUiObjectClassId", hr); return hr; } STDMETHODIMP CInboundConnection::Rename ( IN PCWSTR pszwNewName) { return E_NOTIMPL; } //+--------------------------------------------------------------------------- // INetInboundConnection // STDMETHODIMP CInboundConnection::GetServerConnectionHandle ( OUT ULONG_PTR* phRasSrvConn) { HRESULT hr = S_OK; // If this is the configuration connection, the server connection // handle better be zero. This is used by the UI object so that it // knows it is the configuration connection. // Assert (FIff (m_fIsConfigConnection, !m_hRasSrvConn)); // Because MIDL doesn't know about HRASSRVCONN's, just make sure // it is the same size as the ULONG_PTR we pass it as. // Assert (sizeof (m_hRasSrvConn) == sizeof (*phRasSrvConn)); *phRasSrvConn = reinterpret_cast(m_hRasSrvConn); TraceError ("CInboundConnection::GetServerConnectionHandle", hr); return hr; } STDMETHODIMP CInboundConnection::InitializeAsConfigConnection ( IN BOOL fStartRemoteAccess) { Assert (!m_fInitialized); // Initialize our members. // m_fIsConfigConnection = TRUE; m_hRasSrvConn = 0; SetName (SzLoadIds (IDS_INBOUND_CONFIG_CONNECTION_NAME)); SetDeviceName (NULL); m_MediaType = NCM_NONE; m_guidId = GUID_InboundConfigConnectionId; // We are now a full-fledged object. // m_fInitialized = TRUE; // Start the service if we were told. // HRESULT hr = S_OK; if (fStartRemoteAccess) { DWORD dwErr = RasSrvInitializeService (); hr = HRESULT_FROM_WIN32 (dwErr); TraceError ("RasSrvInitializeService", hr); } TraceError ("CInboundConnection::InitializeAsConfigConnection", hr); return hr; } //+--------------------------------------------------------------------------- // IPersistNetConnection // STDMETHODIMP CInboundConnection::GetClassID ( OUT CLSID* pclsid) { HRESULT hr = S_OK; // Validate parameters. // if (!pclsid) { hr = E_POINTER; } else { *pclsid = CLSID_InboundConnection; } TraceError ("CInboundConnection::GetClassID", hr); return hr; } static const WCHAR c_chwLead = 0x19; static const WCHAR c_chwTrail = 0x07; STDMETHODIMP CInboundConnection::GetSizeMax ( OUT ULONG* pcbSize) { HRESULT hr = S_OK; // Validate parameters. // if (!pcbSize) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { // Size the buffer for the following form: // +--------------------------------------------------------------+ // |0x19...\00x07| // +--------------------------------------------------------------+ // // m_strDeviceName may be empty, in which case we want to still // store the null-terminator. Don't use PszwDeviceName() as it // returns NULL when m_strDeviceName is empty. // *pcbSize = sizeof (c_chwLead) + sizeof (m_fIsConfigConnection) + sizeof (m_hRasSrvConn) + CbOfSzAndTerm (PszwName()) + CbOfSzAndTerm (m_strDeviceName.c_str()) + sizeof (m_MediaType) + sizeof (m_guidId) + sizeof (c_chwTrail); } TraceError ("CInboundConnection::GetSizeMax", hr); return hr; } STDMETHODIMP CInboundConnection::Load ( IN const BYTE* pbBuf, IN ULONG cbSize) { // The theoretical minimum size for the buffer. Computed // as the number of bytes in the following minimum string: // const ULONG c_cbSizeMin = sizeof (c_chwLead) + sizeof (m_fIsConfigConnection) + sizeof (m_hRasSrvConn) + 4 + // 4 bytes for 1 UNICODE char and NULL 2 + // 1 UNICODE NULL for empty device name sizeof (m_MediaType) + sizeof (m_guidId) + sizeof (c_chwTrail); HRESULT hr = E_INVALIDARG; // Validate parameters. // if (!pbBuf) { hr = E_POINTER; } else if (cbSize < c_cbSizeMin) { hr = E_INVALIDARG; } // We can only accept one call on this method and only if we're not // already initialized. // else if (m_fInitialized) { hr = E_UNEXPECTED; } else { // The buffer *should* look like this: // +--------------------------------------------------------------+ // |0x19...\00x07| // +--------------------------------------------------------------+ // const WCHAR * pchw; const WCHAR * pchwMax; const BOOL UNALIGNED * pfIsConfigConnection; BOOL fIsConfigConnection; const HRASSRVCONN UNALIGNED * phRasSrvCon; HRASSRVCONN hRasSrvConn; PCWSTR pszwName; PCWSTR pszwDeviceName; const NETCON_MEDIATYPE UNALIGNED * pMediaType; const GUID UNALIGNED * pguidTemp; const GUID UNALIGNED * pguidId; NETCON_MEDIATYPE MediaType; pchw = reinterpret_cast(pbBuf); // The last valid pointer for the embedded strings. // pchwMax = reinterpret_cast(pbBuf + cbSize - (sizeof (m_MediaType) + sizeof (m_guidId) + sizeof (c_chwTrail))); // Check our lead byte. // if (c_chwLead != *pchw) { goto finished; } pchw++; // Get m_fIsConfigConnection. // pfIsConfigConnection = reinterpret_cast(pchw); CopyMemory(&fIsConfigConnection, pfIsConfigConnection, sizeof(fIsConfigConnection)); pfIsConfigConnection++; // Get m_hRasSrvConn. // phRasSrvCon = reinterpret_cast(pfIsConfigConnection); CopyMemory(&hRasSrvConn, phRasSrvCon, sizeof(hRasSrvConn)); phRasSrvCon++; // Get m_strName. Search for the terminating null and make sure // we find it before the end of the buffer. Using lstrlen to skip // the string can result in an AV in the event the string is not // actually null-terminated. // pchw = reinterpret_cast(phRasSrvCon); for (pszwName = pchw; ; pchw++) { if (pchw >= pchwMax) { goto finished; } if (0 == *pchw) { pchw++; break; } } // Get m_strDeviceName. Search for the terminating null and make // sure we find it before the end of the buffer. // for (pszwDeviceName = pchw; ; pchw++) { if (pchw >= pchwMax) { goto finished; } if (0 == *pchw) { pchw++; break; } } // Get m_MediaType. // pMediaType = reinterpret_cast(pchw); CopyMemory(&MediaType, pMediaType, sizeof(MediaType)); pMediaType++; // Get m_guidId. // pguidTemp = reinterpret_cast(pMediaType); pguidId = pguidTemp; pguidTemp++; // Check our trail byte. // pchw = reinterpret_cast(pguidTemp); if (c_chwTrail != *pchw) { goto finished; } // If we're the configuration object, we can't have a connection // HANDLE and vice-versa. // if ((fIsConfigConnection && hRasSrvConn) || (!fIsConfigConnection && !hRasSrvConn)) { goto finished; } // We are now a full-fledged object. // m_fIsConfigConnection = fIsConfigConnection; m_hRasSrvConn = hRasSrvConn; SetName (pszwName); SetDeviceName (pszwDeviceName); m_MediaType = MediaType; CopyMemory(&m_guidId, pguidId, sizeof(m_guidId)); m_fInitialized = TRUE; hr = S_OK; finished: ; } TraceError ("CInboundConnection::Load", hr); return hr; } STDMETHODIMP CInboundConnection::Save ( OUT BYTE* pbBuf, IN ULONG cbSize) { HRESULT hr = S_OK; // Validate parameters. // if (!pbBuf) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { // Make sure the user's buffer is big enough. // ULONG cbSizeRequired; SideAssert (SUCCEEDED(GetSizeMax(&cbSizeRequired))); if (cbSize < cbSizeRequired) { hr = E_INVALIDARG; } else { // Make the buffer look like this when we're done: // +--------------------------------------------------------------+ // |0x19...\00x07| // +--------------------------------------------------------------+ // WCHAR* pchw = reinterpret_cast(pbBuf); // Put our lead byte. // *pchw = c_chwLead; pchw++; // Put m_fIsConfigConnection. // BOOL UNALIGNED *pfIsConfigConnection = reinterpret_cast(pchw); CopyMemory(pfIsConfigConnection, &m_fIsConfigConnection, sizeof(m_fIsConfigConnection)); pfIsConfigConnection++; // Put m_hRasSrvConn. // HRASSRVCONN UNALIGNED *phRasSrvCon = reinterpret_cast(pfIsConfigConnection); CopyMemory(phRasSrvCon, &m_hRasSrvConn, sizeof(m_hRasSrvConn)); phRasSrvCon++; // Put m_strName. // pchw = reinterpret_cast(phRasSrvCon); lstrcpyW (pchw, PszwName()); pchw += lstrlenW (PszwName()) + 1; // Put m_strDeviceName. // lstrcpyW (pchw, m_strDeviceName.c_str()); pchw += m_strDeviceName.length() + 1; // Put m_MediaType. // NETCON_MEDIATYPE UNALIGNED *pMediaType = reinterpret_cast(pchw); CopyMemory(pMediaType, &m_MediaType, sizeof(m_MediaType)); pMediaType++; // Put m_guidId. // GUID UNALIGNED *pguidId = reinterpret_cast(pMediaType); CopyMemory(pguidId, &m_guidId, sizeof(m_guidId)); pguidId++; // Put our trail byte. // pchw = reinterpret_cast(pguidId); *pchw = c_chwTrail; pchw++; AssertSz (pbBuf + cbSizeRequired == (BYTE*)pchw, "pch isn't pointing where it should be."); } } TraceError ("CInboundConnection::Save", hr); return hr; } #define ID_DEVICE_DATABASE 1 #define ID_MISC_DATABASE 8 //+--------------------------------------------------------------------------- // // Function: IconStateChanged // // Purpose: Fires an event to notify NetShell of a Change occuring in an // incoming connection. // // Arguments: // // Returns: S_OK on success; error otherwise // // Author: ckotze 25 September 2000 // // Notes: // HRESULT CInboundConnection::IconStateChanged() { HRESULT hr = S_OK; IncomingEventNotify(REFRESH_ALL, NULL, NULL, NULL); return hr; }