/* * PROJECT: ReactOS Shell * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: CNetConnectionManager class * COPYRIGHT: Copyright 2008 Johannes Anderwald (johannes.anderwald@reactos.org) */ #include "precomp.h" VOID NormalizeOperStatus(MIB_IFROW *IfEntry, NETCON_PROPERTIES * Props); /*************************************************************** * INetConnection Interface */ HRESULT WINAPI CNetConnection::Initialize(PINetConnectionItem pItem) { m_Props = pItem->Props; m_dwAdapterIndex = pItem->dwAdapterIndex; if (pItem->Props.pszwName) { m_Props.pszwName = static_cast(CoTaskMemAlloc((wcslen(pItem->Props.pszwName)+1)*sizeof(WCHAR))); if (m_Props.pszwName) wcscpy(m_Props.pszwName, pItem->Props.pszwName); } if (pItem->Props.pszwDeviceName) { m_Props.pszwDeviceName = static_cast(CoTaskMemAlloc((wcslen(pItem->Props.pszwDeviceName)+1)*sizeof(WCHAR))); if (m_Props.pszwDeviceName) wcscpy(m_Props.pszwDeviceName, pItem->Props.pszwDeviceName); } return S_OK; } CNetConnection::~CNetConnection() { CoTaskMemFree(m_Props.pszwName); CoTaskMemFree(m_Props.pszwDeviceName); } HRESULT WINAPI CNetConnection::Connect() { return E_NOTIMPL; } BOOL FindNetworkAdapter(HDEVINFO hInfo, SP_DEVINFO_DATA *pDevInfo, LPWSTR pGuid) { DWORD dwIndex, dwSize; HKEY hSubKey; WCHAR szNetCfg[50]; WCHAR szDetail[200] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\"; dwIndex = 0; do { ZeroMemory(pDevInfo, sizeof(SP_DEVINFO_DATA)); pDevInfo->cbSize = sizeof(SP_DEVINFO_DATA); /* get device info */ if (!SetupDiEnumDeviceInfo(hInfo, dwIndex++, pDevInfo)) break; /* get device software registry path */ if (!SetupDiGetDeviceRegistryPropertyW(hInfo, pDevInfo, SPDRP_DRIVER, NULL, (LPBYTE)&szDetail[39], sizeof(szDetail)/sizeof(WCHAR) - 40, &dwSize)) break; /* open device registry key */ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szDetail, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS) break; /* query NetCfgInstanceId for current device */ dwSize = sizeof(szNetCfg); if (RegQueryValueExW(hSubKey, L"NetCfgInstanceId", NULL, NULL, (LPBYTE)szNetCfg, &dwSize) != ERROR_SUCCESS) { RegCloseKey(hSubKey); break; } RegCloseKey(hSubKey); if (!_wcsicmp(pGuid, szNetCfg)) { return TRUE; } } while (TRUE); return FALSE; } HRESULT WINAPI CNetConnection::Disconnect() { HKEY hKey; NETCON_PROPERTIES * pProperties; LPOLESTR pDisplayName; WCHAR szPath[200]; DWORD dwSize, dwType; LPWSTR pPnp; HDEVINFO hInfo; SP_DEVINFO_DATA DevInfo; SP_PROPCHANGE_PARAMS PropChangeParams; HRESULT hr; hr = GetProperties(&pProperties); if (FAILED_UNEXPECTEDLY(hr)) return hr; hInfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT ); if (!hInfo) { NcFreeNetconProperties(pProperties); return E_FAIL; } if (FAILED(StringFromCLSID((CLSID)pProperties->guidId, &pDisplayName))) { NcFreeNetconProperties(pProperties); SetupDiDestroyDeviceInfoList(hInfo); return E_FAIL; } NcFreeNetconProperties(pProperties); if (FindNetworkAdapter(hInfo, &DevInfo, pDisplayName)) { PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; //; PropChangeParams.StateChange = DICS_DISABLE; PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC; PropChangeParams.HwProfile = 0; if (SetupDiSetClassInstallParams(hInfo, &DevInfo, &PropChangeParams.ClassInstallHeader, sizeof(SP_PROPCHANGE_PARAMS))) { SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hInfo, &DevInfo); } } SetupDiDestroyDeviceInfoList(hInfo); swprintf(szPath, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", pDisplayName); CoTaskMemFree(pDisplayName); if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS) return E_FAIL; dwSize = 0; if (RegQueryValueExW(hKey, L"PnpInstanceID", NULL, &dwType, NULL, &dwSize) != ERROR_SUCCESS || dwType != REG_SZ) { RegCloseKey(hKey); return E_FAIL; } pPnp = static_cast(CoTaskMemAlloc(dwSize)); if (!pPnp) { RegCloseKey(hKey); return E_FAIL; } if (RegQueryValueExW(hKey, L"PnpInstanceID", NULL, &dwType, (LPBYTE)pPnp, &dwSize) != ERROR_SUCCESS) { CoTaskMemFree(pPnp); RegCloseKey(hKey); return E_FAIL; } RegCloseKey(hKey); swprintf(szPath, L"System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Enum\\%s", pPnp); CoTaskMemFree(pPnp); if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szPath, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) return E_FAIL; dwSize = 1; /* enable = 0, disable = 1 */ RegSetValueExW(hKey, L"CSConfigFlags", 0, REG_DWORD, (LPBYTE)&dwSize, sizeof(DWORD)); RegCloseKey(hKey); return S_OK; } HRESULT WINAPI CNetConnection::Delete() { return E_NOTIMPL; } HRESULT WINAPI CNetConnection::Duplicate( LPCWSTR pszwDuplicateName, INetConnection **ppCon) { return E_NOTIMPL; } HRESULT WINAPI CNetConnection::GetProperties(NETCON_PROPERTIES **ppProps) { MIB_IFROW IfEntry; HKEY hKey; LPOLESTR pStr; WCHAR szName[140]; DWORD dwShowIcon, dwNotifyDisconnect, dwType, dwSize; NETCON_PROPERTIES * pProperties; HRESULT hr; if (!ppProps) return E_POINTER; pProperties = static_cast(CoTaskMemAlloc(sizeof(NETCON_PROPERTIES))); if (!pProperties) return E_OUTOFMEMORY; CopyMemory(pProperties, &m_Props, sizeof(NETCON_PROPERTIES)); pProperties->pszwName = NULL; if (m_Props.pszwDeviceName) { pProperties->pszwDeviceName = static_cast(CoTaskMemAlloc((wcslen(m_Props.pszwDeviceName)+1)*sizeof(WCHAR))); if (pProperties->pszwDeviceName) wcscpy(pProperties->pszwDeviceName, m_Props.pszwDeviceName); } *ppProps = pProperties; /* get updated adapter characteristics */ ZeroMemory(&IfEntry, sizeof(IfEntry)); IfEntry.dwIndex = m_dwAdapterIndex; if (GetIfEntry(&IfEntry) != NO_ERROR) return NOERROR; NormalizeOperStatus(&IfEntry, pProperties); hr = StringFromCLSID((CLSID)m_Props.guidId, &pStr); if (SUCCEEDED(hr)) { wcscpy(szName, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"); wcscat(szName, pStr); wcscat(szName, L"\\Connection"); if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(dwShowIcon); if (RegQueryValueExW(hKey, L"ShowIcon", NULL, &dwType, (LPBYTE)&dwShowIcon, &dwSize) == ERROR_SUCCESS && dwType == REG_DWORD) { if (dwShowIcon) pProperties->dwCharacter |= NCCF_SHOW_ICON; else pProperties->dwCharacter &= ~NCCF_SHOW_ICON; } dwSize = sizeof(dwNotifyDisconnect); if (RegQueryValueExW(hKey, L"IpCheckingEnabled", NULL, &dwType, (LPBYTE)&dwNotifyDisconnect, &dwSize) == ERROR_SUCCESS && dwType == REG_DWORD) { if (dwNotifyDisconnect) pProperties->dwCharacter |= NCCF_NOTIFY_DISCONNECTED; else pProperties->dwCharacter &= ~NCCF_NOTIFY_DISCONNECTED; } dwSize = sizeof(szName); if (RegQueryValueExW(hKey, L"Name", NULL, &dwType, (LPBYTE)szName, &dwSize) == ERROR_SUCCESS) { /* use updated name */ dwSize = wcslen(szName) + 1; pProperties->pszwName = static_cast(CoTaskMemAlloc(dwSize * sizeof(WCHAR))); if (pProperties->pszwName) CopyMemory(pProperties->pszwName, szName, dwSize * sizeof(WCHAR)); } else { /* use cached name */ if (m_Props.pszwName) { pProperties->pszwName = static_cast(CoTaskMemAlloc((wcslen(m_Props.pszwName)+1)*sizeof(WCHAR))); if (pProperties->pszwName) wcscpy(pProperties->pszwName, m_Props.pszwName); } } RegCloseKey(hKey); } CoTaskMemFree(pStr); } /* Enable 'Rename' and 'Delete' for Adminstrators only */ if (IsUserAdmin()) { pProperties->dwCharacter |= NCCF_ALLOW_RENAME; /* Virtual network interfaces can be deleted */ if (IfEntry.dwType == IF_TYPE_TUNNEL) { pProperties->dwCharacter |= NCCF_ALLOW_REMOVAL; } } else { pProperties->dwCharacter &= ~(NCCF_ALLOW_RENAME | NCCF_ALLOW_REMOVAL); } return S_OK; } HRESULT WINAPI CNetConnection::GetUiObjectClassId(CLSID *pclsid) { if (m_Props.MediaType == NCM_LAN) { CopyMemory(pclsid, &CLSID_LanConnectionUi, sizeof(CLSID)); return S_OK; } return E_NOTIMPL; } HRESULT WINAPI CNetConnection::Rename(LPCWSTR pszwDuplicateName) { WCHAR szName[140]; LPOLESTR pStr; DWORD dwSize; HKEY hKey; HRESULT hr; if (pszwDuplicateName == NULL || wcslen(pszwDuplicateName) == 0) return S_OK; if (m_Props.pszwName) { CoTaskMemFree(m_Props.pszwName); m_Props.pszwName = NULL; } dwSize = (wcslen(pszwDuplicateName) + 1) * sizeof(WCHAR); m_Props.pszwName = static_cast(CoTaskMemAlloc(dwSize)); if (m_Props.pszwName == NULL) return E_OUTOFMEMORY; wcscpy(m_Props.pszwName, pszwDuplicateName); hr = StringFromCLSID((CLSID)m_Props.guidId, &pStr); if (SUCCEEDED(hr)) { wcscpy(szName, L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"); wcscat(szName, pStr); wcscat(szName, L"\\Connection"); if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS) { RegSetValueExW(hKey, L"Name", NULL, REG_SZ, (LPBYTE)m_Props.pszwName, dwSize); RegCloseKey(hKey); } CoTaskMemFree(pStr); } return hr; } HRESULT WINAPI CNetConnection_CreateInstance(PINetConnectionItem pItem, REFIID riid, LPVOID * ppv) { return ShellObjectCreatorInit(pItem, riid, ppv); } CNetConnectionManager::CNetConnectionManager() : m_pHead(NULL), m_pCurrent(NULL) { } HRESULT WINAPI CNetConnectionManager::EnumConnections( NETCONMGR_ENUM_FLAGS Flags, IEnumNetConnection **ppEnum) { TRACE("EnumConnections\n"); if (!ppEnum) return E_POINTER; if (Flags != NCME_DEFAULT) return E_FAIL; *ppEnum = static_cast(this); AddRef(); return S_OK; } /*************************************************************** * IEnumNetConnection Interface */ HRESULT WINAPI CNetConnectionManager::Next( ULONG celt, INetConnection **rgelt, ULONG *pceltFetched) { HRESULT hr; if (!pceltFetched || !rgelt) return E_POINTER; if (celt != 1) return E_FAIL; if (!m_pCurrent) return S_FALSE; hr = CNetConnection_CreateInstance(m_pCurrent, IID_PPV_ARG(INetConnection, rgelt)); m_pCurrent = m_pCurrent->Next; return hr; } HRESULT WINAPI CNetConnectionManager::Skip(ULONG celt) { while (m_pCurrent && celt-- > 0) m_pCurrent = m_pCurrent->Next; if (celt) return S_FALSE; else return S_OK; } HRESULT WINAPI CNetConnectionManager::Reset() { m_pCurrent = m_pHead; return S_OK; } HRESULT WINAPI CNetConnectionManager::Clone(IEnumNetConnection **ppenum) { return E_NOTIMPL; } BOOL GetAdapterIndexFromNetCfgInstanceId(PIP_ADAPTER_INFO pAdapterInfo, LPWSTR szNetCfg, PDWORD pIndex) { WCHAR szBuffer[50]; IP_ADAPTER_INFO * pCurrentAdapter; pCurrentAdapter = pAdapterInfo; while (pCurrentAdapter) { szBuffer[0] = L'\0'; if (MultiByteToWideChar(CP_ACP, 0, pCurrentAdapter->AdapterName, -1, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0]))) { szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; } if (!_wcsicmp(szBuffer, szNetCfg)) { *pIndex = pCurrentAdapter->Index; return TRUE; } pCurrentAdapter = pCurrentAdapter->Next; } return FALSE; } VOID NormalizeOperStatus( MIB_IFROW *IfEntry, NETCON_PROPERTIES * Props) { switch (IfEntry->dwOperStatus) { case MIB_IF_OPER_STATUS_NON_OPERATIONAL: Props->Status = NCS_HARDWARE_DISABLED; break; case MIB_IF_OPER_STATUS_UNREACHABLE: Props->Status = NCS_DISCONNECTED; break; case MIB_IF_OPER_STATUS_DISCONNECTED: Props->Status = NCS_MEDIA_DISCONNECTED; break; case MIB_IF_OPER_STATUS_CONNECTING: Props->Status = NCS_CONNECTING; break; case MIB_IF_OPER_STATUS_CONNECTED: Props->Status = NCS_CONNECTED; break; case MIB_IF_OPER_STATUS_OPERATIONAL: Props->Status = NCS_CONNECTED; break; default: break; } } HRESULT CNetConnectionManager::EnumerateINetConnections() { DWORD dwSize, dwResult, dwIndex, dwAdapterIndex, dwShowIcon, dwNotifyDisconnect; MIB_IFTABLE *pIfTable; MIB_IFROW IfEntry; IP_ADAPTER_INFO * pAdapterInfo; HDEVINFO hInfo; SP_DEVINFO_DATA DevInfo; HKEY hSubKey; WCHAR szNetCfg[50]; WCHAR szAdapterNetCfg[50]; WCHAR szDetail[200] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\"; WCHAR szName[130] = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"; PINetConnectionItem pCurrent = NULL; /* get the IfTable */ dwSize = 0; if (GetIfTable(NULL, &dwSize, TRUE) != ERROR_INSUFFICIENT_BUFFER) return E_FAIL; pIfTable = static_cast(CoTaskMemAlloc(dwSize)); if (!pIfTable) return E_OUTOFMEMORY; dwResult = GetIfTable(pIfTable, &dwSize, TRUE); if (dwResult != NO_ERROR) { CoTaskMemFree(pIfTable); return HRESULT_FROM_WIN32(dwResult); } dwSize = 0; dwResult = GetAdaptersInfo(NULL, &dwSize); if (dwResult!= ERROR_BUFFER_OVERFLOW) { CoTaskMemFree(pIfTable); return HRESULT_FROM_WIN32(dwResult); } pAdapterInfo = static_cast(CoTaskMemAlloc(dwSize)); if (!pAdapterInfo) { CoTaskMemFree(pIfTable); return E_OUTOFMEMORY; } dwResult = GetAdaptersInfo(pAdapterInfo, &dwSize); if (dwResult != NO_ERROR) { CoTaskMemFree(pIfTable); CoTaskMemFree(pAdapterInfo); return HRESULT_FROM_WIN32(dwResult); } hInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT ); if (!hInfo) { CoTaskMemFree(pIfTable); CoTaskMemFree(pAdapterInfo); return E_FAIL; } dwIndex = 0; do { ZeroMemory(&DevInfo, sizeof(SP_DEVINFO_DATA)); DevInfo.cbSize = sizeof(DevInfo); /* get device info */ if (!SetupDiEnumDeviceInfo(hInfo, dwIndex++, &DevInfo)) break; /* get device software registry path */ if (!SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DRIVER, NULL, (LPBYTE)&szDetail[39], sizeof(szDetail)/sizeof(WCHAR) - 40, &dwSize)) break; /* open device registry key */ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szDetail, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS) break; /* query NetCfgInstanceId for current device */ dwSize = sizeof(szNetCfg); if (RegQueryValueExW(hSubKey, L"NetCfgInstanceId", NULL, NULL, (LPBYTE)szNetCfg, &dwSize) != ERROR_SUCCESS) { RegCloseKey(hSubKey); break; } RegCloseKey(hSubKey); /* get the current adapter index from NetCfgInstanceId */ if (!GetAdapterIndexFromNetCfgInstanceId(pAdapterInfo, szNetCfg, &dwAdapterIndex)) continue; /* get detailed adapter info */ ZeroMemory(&IfEntry, sizeof(IfEntry)); IfEntry.dwIndex = dwAdapterIndex; if (GetIfEntry(&IfEntry) != NO_ERROR) break; /* allocate new INetConnectionItem */ PINetConnectionItem pNew = static_cast(CoTaskMemAlloc(sizeof(INetConnectionItem))); if (!pNew) break; ZeroMemory(pNew, sizeof(INetConnectionItem)); pNew->dwAdapterIndex = dwAdapterIndex; /* store NetCfgInstanceId */ CLSIDFromString(szNetCfg, &pNew->Props.guidId); NormalizeOperStatus(&IfEntry, &pNew->Props); switch (IfEntry.dwType) { case IF_TYPE_ETHERNET_CSMACD: pNew->Props.MediaType = NCM_LAN; break; case IF_TYPE_IEEE80211: pNew->Props.MediaType = NCM_SHAREDACCESSHOST_RAS; break; default: break; } /* open network connections details */ wcscpy(&szName[80], szNetCfg); wcscpy(&szName[118], L"\\Connection"); if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szName, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) { /* retrieve name of connection */ dwSize = sizeof(szAdapterNetCfg); if (RegQueryValueExW(hSubKey, L"Name", NULL, NULL, (LPBYTE)szAdapterNetCfg, &dwSize) == ERROR_SUCCESS) { pNew->Props.pszwName = static_cast(CoTaskMemAlloc((wcslen(szAdapterNetCfg)+1) * sizeof(WCHAR))); if (pNew->Props.pszwName) wcscpy(pNew->Props.pszwName, szAdapterNetCfg); } dwSize = sizeof(dwShowIcon); if (RegQueryValueExW(hSubKey, L"ShowIcon", NULL, NULL, (LPBYTE)&dwShowIcon, &dwSize) == ERROR_SUCCESS) { if (dwShowIcon) pNew->Props.dwCharacter |= NCCF_SHOW_ICON; } dwSize = sizeof(dwNotifyDisconnect); if (RegQueryValueExW(hSubKey, L"IpCheckingEnabled", NULL, NULL, (LPBYTE)&dwNotifyDisconnect, &dwSize) == ERROR_SUCCESS) { if (dwNotifyDisconnect) pNew->Props.dwCharacter |= NCCF_NOTIFY_DISCONNECTED; } RegCloseKey(hSubKey); } /* Get the adapter device description */ dwSize = 0; SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DEVICEDESC, NULL, NULL, 0, &dwSize); if (dwSize != 0) { pNew->Props.pszwDeviceName = static_cast(CoTaskMemAlloc(dwSize)); if (pNew->Props.pszwDeviceName) SetupDiGetDeviceRegistryPropertyW(hInfo, &DevInfo, SPDRP_DEVICEDESC, NULL, (PBYTE)pNew->Props.pszwDeviceName, dwSize, &dwSize); } if (pCurrent) pCurrent->Next = pNew; else m_pHead = pNew; pCurrent = pNew; } while (TRUE); CoTaskMemFree(pIfTable); CoTaskMemFree(pAdapterInfo); SetupDiDestroyDeviceInfoList(hInfo); m_pCurrent = m_pHead; return (m_pHead != NULL ? S_OK : S_FALSE); } HRESULT CNetConnectionManager::Initialize() { HRESULT hr = EnumerateINetConnections(); if (FAILED_UNEXPECTEDLY(hr)) { /* If something went wrong during the enumeration print an error don't enumerate anything */ m_pCurrent = m_pHead = NULL; return S_FALSE; } return S_OK; } HRESULT WINAPI CNetConnectionManager_CreateInstance(REFIID riid, LPVOID * ppv) { #if USE_CUSTOM_CONMGR return ShellObjectCreatorInit(riid, ppv); #else return CoCreateInstance(CLSID_ConnectionManager, NULL, CLSCTX_ALL, riid, ppv); #endif }