/*++ Copyright (c) 1999-2001 Microsoft Corporation Module Name: svcapis.cpp Abstract: This module implements routines to assist CUSTOM Mode Value SSR Knowledge Base processing. Author: Vishnu Patankar (VishnuP) - Oct 2001 Environment: User mode only. Exported Functions: svcapis.def Revision History: Created - Oct 2001 --*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CComModule _Module; #include #include #include #include #include #include #include #include typedef DWORD (WINAPI *PFGETDOMAININFO)(LPCWSTR, DSROLE_PRIMARY_DOMAIN_INFO_LEVEL, PBYTE *); typedef VOID (WINAPI *PFDSFREE)( PVOID ); typedef BOOLEAN (WINAPI *PFREMOTEASSISTANCEENABLED)(VOID); DWORD SvcapispQueryServiceStartupType( IN PWSTR pszMachineName, IN PWSTR pszServiceName, OUT BYTE *pbyStartupType ); HRESULT SvcapispGetRemoteOSVersionInfo( IN PWSTR pszMachineName, OUT OSVERSIONINFOEX *posVersionInfo ); BOOL WINAPI DllMain( IN HANDLE DllHandle, IN ULONG ulReason, IN LPVOID Reserved ) /*++ Routine Description: Typical DllMain functionality Arguments: DllHandle ulReason Reserved Return: TRUE if successfully initialized, FALSE otherwise --*/ { switch(ulReason) { case DLL_PROCESS_ATTACH: // // Fall through to process first thread // case DLL_THREAD_ATTACH: break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_DETACH: break; } return TRUE; } STDAPI DllRegisterServer( void ) /*++ Routine Description: Registers dll Arguments: Return: S_OK if successful --*/ { return S_OK; } STDAPI DllUnregisterServer( void ) /*++ Routine Description: Unregisters dll Arguments: Return: S_OK if successful --*/ { return S_OK; } DWORD SvcapispQueryServiceStartupType( IN PWSTR pszMachineName, IN PWSTR pszServiceName, OUT BYTE *pbyStartupType ) /*++ Routine Description: Routine called to check service startup type Arguments: pszMachineName - name of machine to evaluate function on pszServiceName - name of service pbyStartupType - startup type Return: Win32 error code ++*/ { DWORD rc = ERROR_SUCCESS; DWORD dwBytesNeeded = 0; SC_HANDLE hService = NULL; LPQUERY_SERVICE_CONFIG pServiceConfig=NULL; SC_HANDLE hScm = NULL; if (pbyStartupType == NULL || pszServiceName == NULL){ return ERROR_INVALID_PARAMETER; } *pbyStartupType = SERVICE_DISABLED; hScm = OpenSCManager( pszMachineName, NULL, GENERIC_READ); if (hScm == NULL) { rc = GetLastError(); goto ExitHandler; } hService = OpenService( hScm, pszServiceName, SERVICE_QUERY_CONFIG | READ_CONTROL ); if ( hService == NULL ) { rc = GetLastError(); goto ExitHandler; } if ( !QueryServiceConfig( hService, NULL, 0, &dwBytesNeeded )) { if (ERROR_INSUFFICIENT_BUFFER != (rc = GetLastError())){ goto ExitHandler; } } rc = ERROR_SUCCESS; pServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_ZEROINIT, dwBytesNeeded); if ( pServiceConfig == NULL ) { rc = ERROR_NOT_ENOUGH_MEMORY; goto ExitHandler; } if ( !QueryServiceConfig( hService, pServiceConfig, dwBytesNeeded, &dwBytesNeeded) ) { rc = GetLastError(); goto ExitHandler; } *pbyStartupType = (BYTE)(pServiceConfig->dwStartType) ; ExitHandler: if (pServiceConfig) { LocalFree(pServiceConfig); } if (hService) { CloseServiceHandle(hService); } if (hScm) { CloseServiceHandle(hScm); } return rc; } DWORD SvcapisIsDomainMember( IN PWSTR pszMachineName, OUT BOOL *pbIsDomainMember ) /*++ Routine Description: Detects if machine is joined to a domain Arguments: pszMachineName - name of machine to evaluate function on pbIsDomainMember - pointer to boolean to fill Return: Win32 error code --*/ { NTSTATUS NtStatus; PPOLICY_DNS_DOMAIN_INFO pDnsDomainInfo=NULL; LSA_HANDLE LsaHandle=NULL; LSA_OBJECT_ATTRIBUTES attributes; SECURITY_QUALITY_OF_SERVICE service; UNICODE_STRING uMachineName; if (pbIsDomainMember == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsDomainMember = FALSE; // // Open the LSA policy first // memset( &attributes, 0, sizeof(attributes) ); attributes.Length = sizeof(attributes); attributes.SecurityQualityOfService = &service; service.Length = sizeof(service); service.ImpersonationLevel= SecurityImpersonation; service.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; service.EffectiveOnly = TRUE; RtlInitUnicodeString(&uMachineName, pszMachineName); NtStatus = LsaOpenPolicy( pszMachineName ? &uMachineName: NULL, &attributes, POLICY_VIEW_LOCAL_INFORMATION, &LsaHandle ); if ( !NT_SUCCESS( NtStatus) ) { goto ExitHandler; } // // query primary domain DNS information // NtStatus = LsaQueryInformationPolicy( LsaHandle, PolicyDnsDomainInformation, (PVOID *)&pDnsDomainInfo ); if ( !NT_SUCCESS( NtStatus) || pDnsDomainInfo == NULL) { goto ExitHandler; } if (pDnsDomainInfo->Sid){ *pbIsDomainMember = TRUE; } ExitHandler: if (pDnsDomainInfo){ LsaFreeMemory(pDnsDomainInfo); } if (LsaHandle){ LsaClose( LsaHandle ); } return(RtlNtStatusToDosError(NtStatus)); } DWORD SvcapisDoPrintSharesExist( IN PWSTR pszMachineName, OUT BOOL *pbPrintSharesExist ) /*++ Routine Description: Detects if print shares exist on machine Arguments: pszMachineName - name of machine to evaluate function on pbPrintSharesExist - pointer to boolean to fill Return: Win32/NetApi error code --*/ { NET_API_STATUS NetStatus; DWORD ParmError = 0; DWORD Status = ERROR_SUCCESS; LPBYTE Buffer = NULL; DWORD EntriesRead = 0; DWORD TotalEntries = 0; LPSHARE_INFO_1 pShareInfo = NULL; if (pbPrintSharesExist == NULL) { return ERROR_INVALID_PARAMETER; } *pbPrintSharesExist = FALSE; NetStatus = NetShareEnum( pszMachineName, 1, &Buffer, MAX_PREFERRED_LENGTH, &EntriesRead, &TotalEntries, NULL ); if (NetStatus != NERR_Success || EntriesRead == 0 || Buffer == NULL) { goto ExitHandler; } pShareInfo = (LPSHARE_INFO_1)Buffer; for (ULONG uIndex=0; uIndex < EntriesRead; uIndex++) { if (pShareInfo[uIndex].shi1_type == STYPE_PRINTQ){ *pbPrintSharesExist = TRUE; break; } } ExitHandler: if (Buffer) { NetApiBufferFree(Buffer); } return NetStatus; } DWORD SvcapisIsRemoteAssistanceEnabled( IN PWSTR pszMachineName, OUT BOOL *pbIsRemoteAssistanceEnabled ) /*++ Routine Description: Detects if remote assistance is enabled on machine Arguments: pszMachineName - name of machine to evaluate function on pbIsRemoteAssistanceEnabled - pointer to boolean to fill Return: Win32 error code --*/ { DWORD rc = ERROR_SUCCESS; OSVERSIONINFOEX osVersionInfo; if (pbIsRemoteAssistanceEnabled == NULL) { return ERROR_INVALID_PARAMETER; } if (!GetVersionEx((LPOSVERSIONINFOW)&osVersionInfo)) { rc = GetLastError(); return E_INVALIDARG; } if (osVersionInfo.dwMajorVersion == 5 && osVersionInfo.dwMajorVersion < 1) { // // remote assistance available on > w2k // return S_OK; } HRESULT hr = S_OK; CComPtr pWbemLocator = NULL; CComPtr pWbemServices = NULL; CComPtr pWbemTsObjectInstance = NULL; CComPtr pWbemEnumObject = NULL; CComBSTR bstrMachineAndNamespace; ULONG nReturned = 0; bstrMachineAndNamespace = pszMachineName; bstrMachineAndNamespace += L"\\root\\cimv2"; hr = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pWbemLocator ); if (FAILED(hr) || pWbemLocator == NULL ) { goto ExitHandler; } hr = pWbemLocator->ConnectServer( bstrMachineAndNamespace, NULL, NULL, NULL, 0L, NULL, NULL, &pWbemServices ); if (FAILED(hr) || pWbemServices == NULL ) { goto ExitHandler; } hr = CoSetProxyBlanket( pWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); if (FAILED(hr)) { goto ExitHandler; } hr = pWbemServices->ExecQuery(CComBSTR(L"WQL"), CComBSTR(L"SELECT * FROM Win32_TerminalServiceSetting"), WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pWbemEnumObject); if (FAILED(hr) || pWbemEnumObject == NULL) { goto ExitHandler; } hr = pWbemEnumObject->Next(WBEM_INFINITE, 1, &pWbemTsObjectInstance, &nReturned); if (FAILED(hr) || pWbemTsObjectInstance == NULL) { goto ExitHandler; } VARIANT vHelp; VariantInit(&vHelp); hr = pWbemTsObjectInstance->Get(CComBSTR(L"Help"), 0, &vHelp, NULL, NULL); if (FAILED(hr)) { goto ExitHandler; } if (V_VT(&vHelp) == VT_NULL) { goto ExitHandler; } ULONG uHelp = V_INT(&vHelp); if (uHelp) { *pbIsRemoteAssistanceEnabled = TRUE; } ExitHandler: if (V_VT(&vHelp) != VT_NULL) { VariantClear( &vHelp ); } return hr; } DWORD SvcapisIsWINSClient( IN PWSTR pszMachineName, OUT BOOL *pbIsWINSClient ) /*++ Routine Description: Detects if machine is a WINS client Arguments: pszMachineName - name of machine to evaluate function on (this API is not remotable) pbIsWINSClient - pointer to boolean to fill Return: Win32 error code --*/ { ULONG ulSize = 0; DWORD rc = ERROR_SUCCESS; PIP_ADAPTER_INFO pAdapterInfo = NULL; if (pbIsWINSClient == NULL) { return ERROR_INVALID_PARAMETER; } if (pszMachineName != NULL) { return ERROR_CALL_NOT_IMPLEMENTED; } *pbIsWINSClient = FALSE; rc = GetAdaptersInfo( NULL, &ulSize); if (rc != ERROR_BUFFER_OVERFLOW && rc != ERROR_INSUFFICIENT_BUFFER ){ goto ExitHandler; } pAdapterInfo = (PIP_ADAPTER_INFO) LocalAlloc(LMEM_ZEROINIT, ulSize); if (pAdapterInfo == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto ExitHandler; } rc = GetAdaptersInfo( pAdapterInfo, &ulSize); if (rc != ERROR_SUCCESS){ goto ExitHandler; } for(PIP_ADAPTER_INFO pCurrAdapterInfo=pAdapterInfo; pCurrAdapterInfo!=NULL; pCurrAdapterInfo=pCurrAdapterInfo->Next){ if (pCurrAdapterInfo->PrimaryWinsServer.IpAddress.String != NULL || pCurrAdapterInfo->SecondaryWinsServer.IpAddress.String != NULL ){ *pbIsWINSClient = TRUE; break; } } ExitHandler: if (pAdapterInfo) { LocalFree(pAdapterInfo); } return rc; } DWORD SvcapisAreTasksScheduled( IN PWSTR pszMachineName, OUT BOOL *pbAreTasksScheduled ) /*++ Routine Description: Detects if at least one task is scheduled Arguments: pszMachineName - name of machine to evaluate function on pbAreTasksScheduled - pointer to boolean to fill Return: Win32 error code --*/ { HRESULT hr = S_OK; CComPtr pITS = NULL; CComPtr pIEnum = NULL; if (pbAreTasksScheduled == NULL) { return ERROR_INVALID_PARAMETER; } *pbAreTasksScheduled = FALSE; hr = CoInitialize(NULL); if (FAILED(hr)){ return hr; } hr = CoCreateInstance(CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskScheduler, (void **) &pITS); if (FAILED(hr) || pITS == NULL ){ goto ExitHandler; } if (pszMachineName != NULL) { hr = pITS->SetTargetComputer((LPCTSTR)pszMachineName); if (SCHED_E_SERVICE_NOT_INSTALLED == hr) { hr = S_OK; goto ExitHandler; } if (FAILED(hr)) { goto ExitHandler; } } hr = pITS->Enum(&pIEnum); if (FAILED(hr) || pIEnum == NULL){ goto ExitHandler; } LPWSTR *lpwszNames = NULL; DWORD dwFetchedTasks = 0; hr = pIEnum->Next(1, &lpwszNames, &dwFetchedTasks); if (S_FALSE == hr){ hr = ERROR_SUCCESS; } if (FAILED(hr)){ goto ExitHandler; } if (dwFetchedTasks > 0 ){ *pbAreTasksScheduled = TRUE; } ExitHandler: if (lpwszNames){ CoTaskMemFree(lpwszNames); } CoUninitialize(); return hr; } DWORD SvcapisUPSAttached( IN PWSTR pszMachineName, OUT BOOL *pbIsUPSAttached ) /*++ Routine Description: Detects if UPS hardware is(was) attached Arguments: pszMachineName - name of machine to evaluate function on pbIsUPSAttached - pointer to boolean to fill Return: Win32 error code --*/ { DWORD rc = ERROR_SUCCESS; HKEY hKeyHklm = HKEY_LOCAL_MACHINE; HKEY hKey = NULL; DWORD RegType; DWORD cbData; DWORD dwOptions = 0; if (pbIsUPSAttached == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsUPSAttached = FALSE; if (pszMachineName) { rc = RegConnectRegistry( pszMachineName, HKEY_LOCAL_MACHINE, &hKeyHklm ); } if (rc != ERROR_SUCCESS) { goto ExitHandler; } rc = RegOpenKeyEx(hKeyHklm, L"SYSTEM\\CurrentControlSet\\Services\\UPS", 0, KEY_READ | KEY_QUERY_VALUE, &hKey ); if (rc != ERROR_SUCCESS) { goto ExitHandler; } cbData = sizeof(DWORD); rc = RegQueryValueEx ( hKey, L"Options", NULL, &RegType, (LPBYTE)&dwOptions, &cbData ); if (rc != ERROR_SUCCESS) { goto ExitHandler; } if (dwOptions & 0x1) { *pbIsUPSAttached = TRUE; } ExitHandler: if (hKeyHklm != HKEY_LOCAL_MACHINE) { RegCloseKey(hKeyHklm); } if (hKey) { RegCloseKey(hKey); } if (rc == ERROR_FILE_NOT_FOUND || rc == ERROR_PATH_NOT_FOUND) { rc = ERROR_SUCCESS; } return rc; } DWORD SvcapisAutoUpdateEnabled( IN PWSTR pszMachineName, OUT BOOL *pbAutoUpdateIsEnabled ) /*++ Routine Description: Detects if Auto Update is enabled Arguments: pszMachineName - name of machine to evaluate function on pbAutoUpdateIsEnabled - pointer to boolean to fill Return: Win32 error code --*/ { DWORD rc = ERROR_SUCCESS; HKEY hKeyHklm = HKEY_LOCAL_MACHINE; HKEY hKey = NULL; DWORD RegType; DWORD cbData; DWORD dwOptions = 0; if (pbAutoUpdateIsEnabled == NULL) { return ERROR_INVALID_PARAMETER; } *pbAutoUpdateIsEnabled = FALSE; if (pszMachineName) { rc = RegConnectRegistry( pszMachineName, HKEY_LOCAL_MACHINE, &hKeyHklm ); } if (rc != ERROR_SUCCESS) { goto ExitHandler; } rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update", 0, KEY_READ | KEY_QUERY_VALUE, &hKey ); if (rc != ERROR_SUCCESS) { goto ExitHandler; } cbData = sizeof(DWORD); rc = RegQueryValueEx ( hKey, L"AUOptions", NULL, &RegType, (LPBYTE)&dwOptions, &cbData ); if (rc != ERROR_SUCCESS) { goto ExitHandler; } if (!(dwOptions & 1)) { *pbAutoUpdateIsEnabled = TRUE; } ExitHandler: if (hKeyHklm != HKEY_LOCAL_MACHINE) { RegCloseKey(hKeyHklm); } if (hKey) { RegCloseKey(hKey); } if (rc == ERROR_FILE_NOT_FOUND || rc == ERROR_PATH_NOT_FOUND) { rc = ERROR_SUCCESS; } return rc; } DWORD ServicesFoundThatAreNotinKB( OUT BOOL *pbIsServiceSatisfiable ) /*++ Routine Description: Detects if service is enabled on machine Arguments: pbIsServiceSatisfiable - pointer to boolean to fill Return: Win32 error code --*/ { if (pbIsServiceSatisfiable == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsServiceSatisfiable = TRUE; return ERROR_SUCCESS; } DWORD SvcapisIsPerfCollectionScheduled( IN PWSTR pszMachineName, OUT BOOL *pbIsPerfCollectionScheduled ) /*++ Routine Description: Detects if perf data is being collected on the machine Arguments: pszMachineName - name of machine to evaluate function on pbIsPerfCollectionScheduled - pointer to boolean to fill Return: Win32 error code --*/ { BYTE byStartupType; DWORD rc; if (pbIsPerfCollectionScheduled == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsPerfCollectionScheduled = FALSE; rc = SvcapispQueryServiceStartupType(pszMachineName, L"SysmonLog", &byStartupType ); if (rc != ERROR_SUCCESS) { goto ExitHandler; } *pbIsPerfCollectionScheduled = (byStartupType == SERVICE_AUTO_START ? TRUE : FALSE); ExitHandler: return rc; } DWORD SvcapisIsSBS( IN PWSTR pszMachineName, OUT BOOL *pbIsSmallBusinessServer ) /*++ Routine Description: Routine called to check if SBS is installed Arguments: pszMachineName - name of machine to evaluate function on pbIsSmallBusinessServer - booolean to fill Return: Win32 error code ++*/ { if (pbIsSmallBusinessServer == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsSmallBusinessServer = FALSE; DWORD rc = ERROR_SUCCESS; HRESULT hr = S_OK; OSVERSIONINFOEX osVersionInfo; osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo); if (NULL == pszMachineName) { if (!GetVersionEx((LPOSVERSIONINFOW)&osVersionInfo)) { rc = GetLastError(); goto ExitHandler; } } else { hr = SvcapispGetRemoteOSVersionInfo( pszMachineName, &osVersionInfo); if (FAILED(hr)) { rc = ERROR_PRODUCT_VERSION; goto ExitHandler; } } if (osVersionInfo.dwMajorVersion == VER_SUITE_SMALLBUSINESS || osVersionInfo.dwMajorVersion == VER_SUITE_SMALLBUSINESS_RESTRICTED) { *pbIsSmallBusinessServer = TRUE; } ExitHandler: return rc; } DWORD SvcapisIsDC( IN PWSTR pszMachineName, OUT BOOL *pbIsDC ) /*++ Routine Description: Detects if machine is a DC Arguments: pszMachineName - name of machine to evaluate function on pbIsDC - pointer to boolean to fill Return: Win32 error code --*/ { DWORD rc = ERROR_SUCCESS; if (pbIsDC == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsDC = FALSE; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole=NULL; HINSTANCE hDsRoleDll = LoadLibrary(TEXT("netapi32.dll")); if ( hDsRoleDll == NULL) { rc = ERROR_MOD_NOT_FOUND; goto ExitHandler; } PVOID pfDsRole; pfDsRole = (PVOID)GetProcAddress( hDsRoleDll, "DsRoleGetPrimaryDomainInformation"); if ( pfDsRole == NULL ){ rc = ERROR_PROC_NOT_FOUND; goto ExitHandler; } rc = (*((PFGETDOMAININFO)pfDsRole))( pszMachineName, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pDsRole ); if (rc != ERROR_SUCCESS || NULL == pDsRole) { goto ExitHandler; } if ( pDsRole->MachineRole == DsRole_RolePrimaryDomainController || pDsRole->MachineRole == DsRole_RoleBackupDomainController ) { *pbIsDC = TRUE; } pfDsRole = (PVOID)GetProcAddress( hDsRoleDll, "DsRoleFreeMemory"); if ( pfDsRole ) { (*((PFDSFREE)pfDsRole))( pDsRole ); } ExitHandler: if (hDsRoleDll) { FreeLibrary(hDsRoleDll); } return(rc); } DWORD SvcapisIsAppModeTS( IN PWSTR pszMachineName, OUT BOOL *pbIsAppModeTS ) /*++ Routine Description: Detects if TS is in app mode Arguments: pszMachineName - name of machine to evaluate function on pbIsAppModeTS - pointer to boolean to fill Return: Win32 error code --*/ { DWORD rc = ERROR_SUCCESS; HKEY hKeyHklm = HKEY_LOCAL_MACHINE; HKEY hKey = NULL; DWORD RegType; DWORD cbData; DWORD dwOptions = 0; OSVERSIONINFOEX osVersionInfo; HRESULT hr = S_OK; if (pbIsAppModeTS == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsAppModeTS = FALSE; // // SSR paradigm for preprocessing remoteability // // if local, try the traditional approach // if remote, dig-into the registry etc. (maybe less reliable) // if (pszMachineName == NULL) { // // local // if (!GetVersionEx((LPOSVERSIONINFOW)&osVersionInfo)) { rc = GetLastError(); goto ExitHandler; } } else { // // remote // hr = SvcapispGetRemoteOSVersionInfo( pszMachineName, &osVersionInfo); if (FAILED(hr)) { rc = ERROR_PRODUCT_VERSION; goto ExitHandler; } } if (osVersionInfo.wSuiteMask & VER_SUITE_TERMINAL && osVersionInfo.wSuiteMask & VER_SUITE_SINGLEUSERTS) { *pbIsAppModeTS = TRUE; } /* rc = RegConnectRegistry( pszMachineName, HKEY_LOCAL_MACHINE, &hKeyHklm ); if (rc != ERROR_SUCCESS) { goto ExitHandler; } rc = RegOpenKeyEx(hKeyHklm, L"System\\CurrentControlSet\\Control\\Terminal Server", 0, KEY_READ | KEY_QUERY_VALUE, &hKey ); if (rc != ERROR_SUCCESS) { goto ExitHandler; } cbData = sizeof(DWORD); rc = RegQueryValueEx ( hKey, L"TSAppCompat", NULL, &RegType, (LPBYTE)&dwOptions, &cbData ); if (rc != ERROR_SUCCESS) { goto ExitHandler; } if (dwOptions & 0x1) { *pbIsAppModeTS = TRUE; } } */ ExitHandler: if (hKeyHklm != HKEY_LOCAL_MACHINE) { RegCloseKey(hKeyHklm); } if (hKey) { RegCloseKey(hKey); } if (rc == ERROR_FILE_NOT_FOUND || rc == ERROR_PATH_NOT_FOUND) { rc = ERROR_SUCCESS; } return rc; } DWORD SvcapisDFSSharesExist( IN PWSTR pszMachineName, OUT BOOL *pbDFSSharesExist ) /*++ Routine Description: Detects if DFS shares exist on machine Arguments: pszMachineName - name of machine to evaluate function on pbDFSSharesExist - pointer to boolean to fill Return: Win32/NetApi error code --*/ { NET_API_STATUS NetStatus; DWORD ParmError = 0; DWORD Status = ERROR_SUCCESS; LPBYTE Buffer = NULL; DWORD EntriesRead = 0; DWORD TotalEntries = 0; LPSHARE_INFO_1 pShareInfo = NULL; if (pbDFSSharesExist == NULL) { return ERROR_INVALID_PARAMETER; } *pbDFSSharesExist = FALSE; NetStatus = NetShareEnum( pszMachineName, 1, &Buffer, MAX_PREFERRED_LENGTH, &EntriesRead, &TotalEntries, NULL ); if (NetStatus != NERR_Success || EntriesRead == 0 || Buffer == NULL) { goto ExitHandler; } pShareInfo = (LPSHARE_INFO_1)Buffer; PSHARE_INFO_1005 pBufShareInfo = NULL; DWORD shi1005_flags; for (ULONG uIndex=0; uIndex < EntriesRead; uIndex++) { if (pShareInfo[uIndex].shi1_type == STYPE_DISKTREE) { NetStatus = NetShareGetInfo( pszMachineName, pShareInfo[uIndex].shi1_netname, 1005, (LPBYTE *) &pBufShareInfo ); if (NetStatus != NERR_Success || pBufShareInfo == NULL) { goto ExitHandler; } shi1005_flags = pBufShareInfo->shi1005_flags; NetApiBufferFree(pBufShareInfo); pBufShareInfo = NULL; if (SHI1005_FLAGS_DFS & shi1005_flags) { *pbDFSSharesExist = TRUE; break; } } } ExitHandler: if (Buffer) { NetApiBufferFree(Buffer); } return NetStatus; } DWORD SvcapisIsUsingDHCP( IN PWSTR pszMachineName, OUT BOOL *pbIsUsingDHCP ) /*++ Routine Description: Detects if any adapter on this machine is using DHCP in its TCP/IP stack Arguments: pszMachineName - name of machine to evaluate function on pbIsUsingDHCP - pointer to boolean to fill Return: Win32 error code --*/ { DWORD rc = ERROR_SUCCESS; DWORD dwOutBufLen = 0; PIP_ADAPTER_ADDRESSES pAdapterAddresses = NULL; if (pbIsUsingDHCP == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsUsingDHCP = FALSE; rc = GetAdaptersAddresses( AF_UNSPEC, 0, NULL, NULL, &dwOutBufLen ); if (ERROR_SUCCESS == rc || (ERROR_SUCCESS != rc && ERROR_BUFFER_OVERFLOW != rc)) { goto ExitHandler; } pAdapterAddresses = (PIP_ADAPTER_ADDRESSES) LocalAlloc(LMEM_ZEROINIT, dwOutBufLen); if ( NULL == pAdapterAddresses) { rc = ERROR_NOT_ENOUGH_MEMORY; goto ExitHandler; } rc = GetAdaptersAddresses( AF_UNSPEC, 0, NULL, pAdapterAddresses, &dwOutBufLen ); if (ERROR_SUCCESS != rc) { goto ExitHandler; } for (PIP_ADAPTER_ADDRESSES pCurrentAddress = pAdapterAddresses; pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next) { if (pCurrentAddress->Flags & IP_ADAPTER_DHCP_ENABLED) { *pbIsUsingDHCP = TRUE; goto ExitHandler; } } ExitHandler: if (pAdapterAddresses) { LocalFree(pAdapterAddresses); } return(rc); } DWORD SvcapisIsUsingDDNS( IN PWSTR pszMachineName, OUT BOOL *pbIsUsingDDNS ) /*++ Routine Description: Detects if any adapter on this machine is using DDNS (DNS is always enabled) in its TCP/IP stack Arguments: pszMachineName - name of machine to evaluate function on pbIsUsingDHCP - pointer to boolean to fill Return: Win32 error code --*/ { DWORD rc = ERROR_SUCCESS; DWORD dwOutBufLen = 0; PIP_ADAPTER_ADDRESSES pAdapterAddresses; if (pbIsUsingDDNS == NULL) { return ERROR_INVALID_PARAMETER; } *pbIsUsingDDNS = FALSE; rc = GetAdaptersAddresses( AF_UNSPEC, 0, NULL, NULL, &dwOutBufLen ); if (ERROR_SUCCESS == rc || (ERROR_SUCCESS != rc && ERROR_BUFFER_OVERFLOW != rc)) { goto ExitHandler; } pAdapterAddresses = (PIP_ADAPTER_ADDRESSES) LocalAlloc(LMEM_ZEROINIT, dwOutBufLen); if ( NULL == pAdapterAddresses) { goto ExitHandler; } rc = GetAdaptersAddresses( AF_UNSPEC, 0, NULL, pAdapterAddresses, &dwOutBufLen ); if (ERROR_SUCCESS != rc) { goto ExitHandler; } for (PIP_ADAPTER_ADDRESSES pCurrentAddress = pAdapterAddresses; pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next) { if (pCurrentAddress->Flags & IP_ADAPTER_DDNS_ENABLED) { *pbIsUsingDDNS = TRUE; goto ExitHandler; } } ExitHandler: if (pAdapterAddresses) { LocalFree(pAdapterAddresses); } return(rc); } HRESULT SvcapispGetRemoteOSVersionInfo( IN PWSTR pszMachineName, OUT OSVERSIONINFOEX *posVersionInfo ) /*++ Routine Description: Routine called to get version info from remote machine via WMI Arguments: pszMachineName - remote machine name posVersionInfo - os version info to fill via WMI queries Return: HRESULT error code ++*/ { HRESULT hr = S_OK; CComPtr pWbemLocator = NULL; CComPtr pWbemServices = NULL; CComPtr pWbemOsObjectInstance = NULL; CComPtr pWbemEnumObject = NULL; CComBSTR bstrMachineAndNamespace; ULONG nReturned = 0; bstrMachineAndNamespace = pszMachineName; bstrMachineAndNamespace += L"\\root\\cimv2"; hr = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pWbemLocator ); if (FAILED(hr) || pWbemLocator == NULL ) { goto ExitHandler; } hr = pWbemLocator->ConnectServer( bstrMachineAndNamespace, NULL, NULL, NULL, 0L, NULL, NULL, &pWbemServices ); if (FAILED(hr) || pWbemServices == NULL ) { goto ExitHandler; } hr = CoSetProxyBlanket( pWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); if (FAILED(hr)) { goto ExitHandler; } hr = pWbemServices->ExecQuery(CComBSTR(L"WQL"), CComBSTR(L"SELECT * FROM Win32_OperatingSystem"), WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pWbemEnumObject); if (FAILED(hr) || pWbemEnumObject == NULL) { goto ExitHandler; } hr = pWbemEnumObject->Next(WBEM_INFINITE, 1, &pWbemOsObjectInstance, &nReturned); if (FAILED(hr) || pWbemOsObjectInstance == NULL) { goto ExitHandler; } VARIANT vVersion; VariantInit(&vVersion); hr = pWbemOsObjectInstance->Get(CComBSTR(L"Version"), 0, &vVersion, NULL, NULL); if (FAILED(hr)) { goto ExitHandler; } if (V_VT(&vVersion) == VT_NULL) { goto ExitHandler; } // // extract the version information into DWORDs since // the return type of this property is BSTR variant // of the form "5.1.2195" // BSTR bstrVersion = V_BSTR(&vVersion); WCHAR szVersion[5]; szVersion[0] = L'\0'; PWSTR pszDot = wcsstr(bstrVersion, L"."); if (NULL == pszDot) { hr = E_INVALIDARG; goto ExitHandler; } wcsncpy(szVersion, bstrVersion, 1); posVersionInfo->dwMajorVersion = (DWORD)_wtoi(szVersion); wcsncpy(szVersion, pszDot+1, 1); posVersionInfo->dwMinorVersion = (DWORD)_wtoi(szVersion); ExitHandler: if (V_VT(&vVersion) != VT_NULL) { VariantClear( &vVersion ); } return hr; }