968 lines
27 KiB
C
968 lines
27 KiB
C
|
//++
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1987 - 2000
|
||
|
//
|
||
|
// Module Name:
|
||
|
//
|
||
|
// ipsec.c
|
||
|
//
|
||
|
// Abstract:
|
||
|
//
|
||
|
// IP Security stats for netdiag
|
||
|
//
|
||
|
// Author:
|
||
|
//
|
||
|
// DKalin - 8/3/1999
|
||
|
//
|
||
|
// Environment:
|
||
|
//
|
||
|
// User mode only.
|
||
|
// Contains NT-specific code.
|
||
|
//
|
||
|
// Revision History:
|
||
|
//
|
||
|
// Changed behavior for Whistler - now we report registry/OU settings only
|
||
|
// More specific code moved to ipseccmd.exe tool
|
||
|
//--
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
#include <snmp.h>
|
||
|
#include "tcpinfo.h"
|
||
|
#include "ipinfo.h"
|
||
|
#include "llinfo.h"
|
||
|
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <winsock2.h>
|
||
|
#include <ipexport.h>
|
||
|
#include <icmpapi.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <assert.h>
|
||
|
#include <tchar.h>
|
||
|
#include <wincrypt.h>
|
||
|
#include <stdio.h>
|
||
|
#include <objbase.h>
|
||
|
#include <dsgetdc.h>
|
||
|
#include <lm.h>
|
||
|
#include <userenv.h>
|
||
|
|
||
|
#define MAXSTRLEN (1024)
|
||
|
#define STRING_TEXT_SIZE 4096
|
||
|
#define NETDIAG_TEXT_LIMIT 3072
|
||
|
|
||
|
// policy source constants
|
||
|
#define PS_NO_POLICY 0
|
||
|
#define PS_DS_POLICY 1
|
||
|
#define PS_LOC_POLICY 2
|
||
|
|
||
|
// magic strings
|
||
|
#define IPSEC_SERVICE_NAME TEXT("policyagent")
|
||
|
#define GPEXT_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions")
|
||
|
TCHAR pcszGPTIPSecKey[] = TEXT("SOFTWARE\\Policies\\Microsoft\\Windows\\IPSEC\\GPTIPSECPolicy");
|
||
|
TCHAR pcszGPTIPSecName[] = TEXT("DSIPSECPolicyName");
|
||
|
TCHAR pcszGPTIPSecFlags[] = TEXT("DSIPSECPolicyFlags");
|
||
|
TCHAR pcszGPTIPSecPath[] = TEXT("DSIPSECPolicyPath");
|
||
|
TCHAR pcszLocIPSecKey[] = TEXT("SOFTWARE\\Policies\\Microsoft\\Windows\\IPSEC\\Policy\\Local");
|
||
|
TCHAR pcszLocIPSecPol[] = TEXT("ActivePolicy");
|
||
|
TCHAR pcszCacheIPSecKey[] = TEXT("SOFTWARE\\Policies\\Microsoft\\Windows\\IPSEC\\Policy\\Cache");
|
||
|
TCHAR pcszIPSecPolicy[] = TEXT("ipsecPolicy");
|
||
|
TCHAR pcszIPSecName[] = TEXT("ipsecName");
|
||
|
TCHAR pcszIPSecDesc[] = TEXT("description");
|
||
|
TCHAR pcszIPSecTimestamp[] = TEXT("whenChanged");
|
||
|
|
||
|
// BAIL_xx defines
|
||
|
#define BAIL_ON_WIN32_ERROR(dwError) \
|
||
|
if (dwError) {\
|
||
|
goto error; \
|
||
|
}
|
||
|
|
||
|
|
||
|
#define BAIL_ON_FAILURE(hr) \
|
||
|
if (FAILED(hr)) {\
|
||
|
goto error; \
|
||
|
}
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
int iPolicySource; // one of the three constants mentioned above
|
||
|
TCHAR pszPolicyName[MAXSTRLEN]; // policy name
|
||
|
TCHAR pszPolicyDesc[MAXSTRLEN]; // policy description
|
||
|
TCHAR pszPolicyPath[MAXSTRLEN]; // policy path (DN or RegKey)
|
||
|
time_t timestamp; // last updated time
|
||
|
} POLICY_INFO, *PPOLICY_INFO;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
SERVICE_STATUS servStat; // service status
|
||
|
QUERY_SERVICE_CONFIG servConfig; // service configuration
|
||
|
} SERVICE_INFO, *PSERVICE_INFO;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
TCHAR pszComputerOU[MAXSTRLEN]; // this computer' OU name
|
||
|
PGROUP_POLICY_OBJECT pGPO; // GPO that is assigning IPSec Policy
|
||
|
TCHAR pszPolicyOU [MAXSTRLEN]; // OU that has the GPO assigned
|
||
|
} DS_POLICY_INFO, *PDS_POLICY_INFO;
|
||
|
|
||
|
DWORD MyFormatMessage ( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId,
|
||
|
LPTSTR lpBuffer, DWORD nSize, va_list *Arguments );
|
||
|
|
||
|
void reportError ( HRESULT hr, NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults );
|
||
|
void reportServiceInfo ( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults );
|
||
|
HRESULT getPolicyInfo ( );
|
||
|
DWORD getMorePolicyInfo ( );
|
||
|
DWORD getServiceInfo ( PSERVICE_INFO pInfo );
|
||
|
PGROUP_POLICY_OBJECT getIPSecGPO ( );
|
||
|
void StringToGuid( TCHAR * szValue, GUID * pGuid );
|
||
|
|
||
|
BOOL bTestSkipped = FALSE;
|
||
|
BOOL bTestPassed = FALSE;
|
||
|
POLICY_INFO piAssignedPolicy;
|
||
|
SERVICE_INFO siIPSecStatus;
|
||
|
DS_POLICY_INFO dpiAssignedPolicy;
|
||
|
TCHAR pszBuf[STRING_TEXT_SIZE];
|
||
|
WCHAR StringTxt[STRING_TEXT_SIZE];
|
||
|
|
||
|
BOOL
|
||
|
IPSecTest(NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
|
||
|
//++
|
||
|
// Description:
|
||
|
// This is IPSec test
|
||
|
//
|
||
|
// Arguments:
|
||
|
// None.
|
||
|
//
|
||
|
// Author:
|
||
|
// DKalin 08/03/99
|
||
|
//--
|
||
|
{
|
||
|
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
HRESULT hr = ERROR_SUCCESS;
|
||
|
PGROUP_POLICY_OBJECT pGPO = NULL;
|
||
|
|
||
|
PrintStatusMessage( pParams, 4, IDS_IPSEC_STATUS_MSG );
|
||
|
|
||
|
InitializeListHead(&pResults->IPSec.lmsgGlobalOutput);
|
||
|
InitializeListHead(&pResults->IPSec.lmsgAdditOutput);
|
||
|
|
||
|
dwError = getServiceInfo(&siIPSecStatus);
|
||
|
|
||
|
if (dwError != ERROR_SUCCESS || siIPSecStatus.servStat.dwCurrentState != SERVICE_RUNNING)
|
||
|
{
|
||
|
// test skipped
|
||
|
bTestSkipped = TRUE;
|
||
|
if (dwError == ERROR_SERVICE_DOES_NOT_EXIST)
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_NOT_INSTALLED );
|
||
|
}
|
||
|
else if (dwError == ERROR_SUCCESS)
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_NOT_STARTED );
|
||
|
reportServiceInfo(pParams, pResults);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// some error
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_NO_INFO );
|
||
|
reportError(dwError, pParams, pResults);
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// test passed
|
||
|
bTestPassed = TRUE;
|
||
|
|
||
|
reportServiceInfo(pParams, pResults);
|
||
|
hr = getPolicyInfo();
|
||
|
|
||
|
if (hr != ERROR_SUCCESS)
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_NO_POLICY_INFO );
|
||
|
reportError(hr, pParams, pResults);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch (piAssignedPolicy.iPolicySource)
|
||
|
{
|
||
|
case PS_NO_POLICY:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_NO_POLICY );
|
||
|
break;
|
||
|
case PS_DS_POLICY:
|
||
|
getMorePolicyInfo();
|
||
|
pGPO = getIPSecGPO();
|
||
|
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_DS_POLICY );
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_POLICY_NAME, piAssignedPolicy.pszPolicyName );
|
||
|
|
||
|
// description and timestamp - not available yet
|
||
|
/*
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_DESCRIPTION, piAssignedPolicy.pszPolicyDesc );
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_TIMESTAMP );
|
||
|
if (piAssignedPolicy.timestamp == 0)
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_ADAPTER_UNKNOWN);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDSSZ_GLOBAL_String, _tctime(&(piAssignedPolicy.timestamp)));
|
||
|
}
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_EmptyLine);
|
||
|
*/
|
||
|
|
||
|
// GPO / OU
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_GPO);
|
||
|
if (pGPO)
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDSSZ_GLOBAL_String, pGPO->lpDisplayName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_ADAPTER_UNKNOWN);
|
||
|
}
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_EmptyLine);
|
||
|
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_OU);
|
||
|
if (pGPO)
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDSSZ_GLOBAL_String, pGPO->lpLink);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_ADAPTER_UNKNOWN);
|
||
|
}
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_EmptyLine);
|
||
|
|
||
|
// policy path
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_POLICY_PATH);
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDSSZ_GLOBAL_StringLine, piAssignedPolicy.pszPolicyPath);
|
||
|
|
||
|
// cleanup GPO
|
||
|
if (pGPO)
|
||
|
{
|
||
|
FreeGPOList (pGPO);
|
||
|
}
|
||
|
break;
|
||
|
case PS_LOC_POLICY:
|
||
|
getMorePolicyInfo();
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_LOC_POLICY );
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_POLICY_NAME, piAssignedPolicy.pszPolicyName );
|
||
|
|
||
|
// description and timestamp
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_DESCRIPTION, piAssignedPolicy.pszPolicyDesc );
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_TIMESTAMP );
|
||
|
if (piAssignedPolicy.timestamp == 0)
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_ADAPTER_UNKNOWN);
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_EmptyLine);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDSSZ_GLOBAL_String, _tctime(&(piAssignedPolicy.timestamp)));
|
||
|
}
|
||
|
|
||
|
// local policy path
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_POLICY_PATH);
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_LOCAL_PATH, piAssignedPolicy.pszPolicyPath);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_IPSECCMD );
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
void IPSecGlobalPrint(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
|
||
|
{
|
||
|
PrintMessage(pParams, IDS_GLOBAL_EmptyLine);
|
||
|
if (bTestSkipped)
|
||
|
{
|
||
|
PrintTestTitleResult(pParams, IDS_IPSEC_LONG, IDS_IPSEC_SHORT, FALSE, S_FALSE, 0);
|
||
|
}
|
||
|
if (bTestPassed)
|
||
|
{
|
||
|
PrintTestTitleResult(pParams, IDS_IPSEC_LONG, IDS_IPSEC_SHORT, TRUE, S_OK, 0);
|
||
|
}
|
||
|
PrintMessageList(pParams, &pResults->IPSec.lmsgGlobalOutput);
|
||
|
PrintMessageList(pParams, &pResults->IPSec.lmsgAdditOutput);
|
||
|
}
|
||
|
|
||
|
|
||
|
void IPSecPerInterfacePrint(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults, INTERFACE_RESULT *pInterfaceResults)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
void IPSecCleanup(IN NETDIAG_PARAMS *pParams,
|
||
|
IN OUT NETDIAG_RESULT *pResults)
|
||
|
{
|
||
|
MessageListCleanUp(&pResults->IPSec.lmsgGlobalOutput);
|
||
|
MessageListCleanUp(&pResults->IPSec.lmsgAdditOutput);
|
||
|
}
|
||
|
|
||
|
//#define MSG_HANDLE_INVALID TEXT("Handle is invalid. Is IPSEC Policy Agent Service running?")
|
||
|
|
||
|
// this will call SDK' FormatMessage function but will also correct some awkward messages
|
||
|
// will work only for FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM flag combination
|
||
|
DWORD MyFormatMessage(
|
||
|
DWORD dwFlags, // source and processing options
|
||
|
LPCVOID lpSource, // pointer to message source
|
||
|
DWORD dwMessageId, // requested message identifier
|
||
|
DWORD dwLanguageId, // language identifier for requested message
|
||
|
LPTSTR lpBuffer, // pointer to message buffer
|
||
|
DWORD nSize, // maximum size of message buffer
|
||
|
va_list *Arguments // pointer to array of message inserts
|
||
|
)
|
||
|
{
|
||
|
LPTSTR* tmp = (LPTSTR*) lpBuffer;
|
||
|
|
||
|
switch (dwMessageId)
|
||
|
{
|
||
|
/* case ERROR_INVALID_HANDLE: // patch for "handle is invalid" message. Suggest to check if service is started
|
||
|
if (dwFlags == (FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM))
|
||
|
{
|
||
|
*tmp = (LPTSTR) malloc((_tcslen(MSG_HANDLE_INVALID)+1)*sizeof(TCHAR));
|
||
|
_tcscpy(*tmp, MSG_HANDLE_INVALID);
|
||
|
return _tcslen(*tmp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FormatMessage(dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,Arguments);
|
||
|
}
|
||
|
*/ default: // call standard method
|
||
|
return FormatMessage(dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,Arguments);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
FUNCTION: getPolicyInfo
|
||
|
|
||
|
PURPOSE: gets information about currently assigned policy
|
||
|
into piAssignedPolicy global structure
|
||
|
INPUT: none
|
||
|
|
||
|
RETURNS: HRESULT. Will return ERROR_SUCCESS if everything is fine.
|
||
|
*********************************************************************/
|
||
|
|
||
|
HRESULT getPolicyInfo ( )
|
||
|
{
|
||
|
LONG lRegistryCallResult;
|
||
|
HKEY hRegKey;
|
||
|
|
||
|
DWORD dwType; // for RegQueryValueEx
|
||
|
DWORD dwBufLen; // for RegQueryValueEx
|
||
|
|
||
|
lRegistryCallResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
|
pcszGPTIPSecKey,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hRegKey);
|
||
|
|
||
|
if (lRegistryCallResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
DWORD dwType;
|
||
|
DWORD dwValue;
|
||
|
DWORD dwLength = sizeof(DWORD);
|
||
|
|
||
|
// query for flags, if flags aint' there or equal to 0, we don't have domain policy
|
||
|
lRegistryCallResult = RegQueryValueEx(hRegKey,
|
||
|
pcszGPTIPSecFlags,
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
(LPBYTE)&dwValue,
|
||
|
&dwLength);
|
||
|
|
||
|
if (lRegistryCallResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
if (dwValue == 0)
|
||
|
lRegistryCallResult = ERROR_FILE_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
// now get name
|
||
|
if (lRegistryCallResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
dwBufLen = MAXSTRLEN*sizeof(TCHAR);
|
||
|
lRegistryCallResult = RegQueryValueEx( hRegKey,
|
||
|
pcszGPTIPSecName,
|
||
|
NULL,
|
||
|
&dwType, // will be REG_SZ
|
||
|
(LPBYTE) pszBuf,
|
||
|
&dwBufLen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (lRegistryCallResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
piAssignedPolicy.iPolicySource = PS_DS_POLICY;
|
||
|
piAssignedPolicy.pszPolicyPath[0] = 0;
|
||
|
_tcscpy(piAssignedPolicy.pszPolicyName, pszBuf);
|
||
|
|
||
|
dwBufLen = MAXSTRLEN*sizeof(TCHAR);
|
||
|
lRegistryCallResult = RegQueryValueEx( hRegKey,
|
||
|
pcszGPTIPSecPath,
|
||
|
NULL,
|
||
|
&dwType, // will be REG_SZ
|
||
|
(LPBYTE) pszBuf,
|
||
|
&dwBufLen);
|
||
|
if (lRegistryCallResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
_tcscpy(piAssignedPolicy.pszPolicyPath, pszBuf);
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hRegKey);
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RegCloseKey(hRegKey);
|
||
|
if (lRegistryCallResult == ERROR_FILE_NOT_FOUND)
|
||
|
{ // DS reg key not found, check local
|
||
|
lRegistryCallResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
|
pcszLocIPSecKey,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hRegKey);
|
||
|
if (lRegistryCallResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
dwBufLen = MAXSTRLEN*sizeof(TCHAR);
|
||
|
lRegistryCallResult = RegQueryValueEx( hRegKey,
|
||
|
pcszLocIPSecPol,
|
||
|
NULL,
|
||
|
&dwType, // will be REG_SZ
|
||
|
(LPBYTE) pszBuf,
|
||
|
&dwBufLen);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return lRegistryCallResult; // return whatever error we got
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hRegKey);
|
||
|
|
||
|
if (lRegistryCallResult == ERROR_FILE_NOT_FOUND)
|
||
|
{ // no policy assigned
|
||
|
piAssignedPolicy.iPolicySource = PS_NO_POLICY;
|
||
|
piAssignedPolicy.pszPolicyPath[0] = 0;
|
||
|
piAssignedPolicy.pszPolicyName[0] = 0;
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{ // read it
|
||
|
lRegistryCallResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
|
pszBuf,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hRegKey);
|
||
|
_tcscpy(piAssignedPolicy.pszPolicyPath, pszBuf);
|
||
|
if (lRegistryCallResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
dwBufLen = MAXSTRLEN*sizeof(TCHAR);
|
||
|
lRegistryCallResult = RegQueryValueEx( hRegKey,
|
||
|
pcszIPSecName,
|
||
|
NULL,
|
||
|
&dwType, // will be REG_SZ
|
||
|
(LPBYTE) pszBuf,
|
||
|
&dwBufLen);
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hRegKey);
|
||
|
|
||
|
if (lRegistryCallResult == ERROR_FILE_NOT_FOUND)
|
||
|
{ // no policy assigned
|
||
|
piAssignedPolicy.iPolicySource = PS_NO_POLICY;
|
||
|
piAssignedPolicy.pszPolicyPath[0] = 0;
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
else if (lRegistryCallResult == ERROR_SUCCESS)
|
||
|
{ // found it
|
||
|
piAssignedPolicy.iPolicySource = PS_LOC_POLICY;
|
||
|
_tcscpy(piAssignedPolicy.pszPolicyName, pszBuf);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (HRESULT) lRegistryCallResult;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
FUNCTION: getServiceInfo
|
||
|
|
||
|
PURPOSE: gets information about current state and configuration of IPSec Service
|
||
|
into *pInfo structure
|
||
|
INPUT: pInfo - pointer to SERVICE_INFO structure which will be updated with current information
|
||
|
TODO:
|
||
|
|
||
|
RETURNS: Win32 error codes. Will return ERROR_SUCCESS if everything is fine.
|
||
|
ERROR_SERVICE_DOES_NOT_EXIST is returned is service is not installed on the system
|
||
|
*********************************************************************/
|
||
|
|
||
|
DWORD getServiceInfo ( OUT PSERVICE_INFO pInfo )
|
||
|
{
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
DWORD dwRequiredSize = 0;
|
||
|
PVOID pLargeConfig = 0;
|
||
|
SC_HANDLE schMan = NULL;
|
||
|
SC_HANDLE schPA = NULL;
|
||
|
|
||
|
if (!pInfo)
|
||
|
{
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
memset(&(pInfo->servStat), 0, sizeof(SERVICE_STATUS));
|
||
|
memset(&(pInfo->servConfig), 0, sizeof(QUERY_SERVICE_CONFIG));
|
||
|
|
||
|
|
||
|
schMan = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||
|
|
||
|
if (schMan == NULL)
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
schPA = OpenService(schMan, IPSEC_SERVICE_NAME, GENERIC_READ);
|
||
|
|
||
|
if (schMan == NULL)
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
if (!QueryServiceStatus(schPA, &(pInfo->servStat)))
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
if (!QueryServiceConfig(schPA, &(pInfo->servConfig), sizeof(QUERY_SERVICE_CONFIG), &dwRequiredSize))
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
if (dwError == ERROR_INSUFFICIENT_BUFFER)
|
||
|
{
|
||
|
pLargeConfig = malloc(dwRequiredSize);
|
||
|
if (!pLargeConfig)
|
||
|
{
|
||
|
goto error;
|
||
|
}
|
||
|
if (!QueryServiceConfig(schPA, (LPQUERY_SERVICE_CONFIG) pLargeConfig, dwRequiredSize, &dwRequiredSize))
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
goto error;
|
||
|
}
|
||
|
// else we just got the information, copy over to *pInfo
|
||
|
memcpy(&(pInfo->servConfig), pLargeConfig, sizeof(QUERY_SERVICE_CONFIG));
|
||
|
dwError = ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
if (schPA)
|
||
|
CloseServiceHandle(schPA);
|
||
|
if (schMan)
|
||
|
CloseServiceHandle(schMan);
|
||
|
if (pLargeConfig)
|
||
|
{
|
||
|
free(pLargeConfig);
|
||
|
}
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
FUNCTION: reportError
|
||
|
|
||
|
PURPOSE: prints out message code and message itself
|
||
|
INPUT: HRESULT - error code
|
||
|
|
||
|
RETURNS: none
|
||
|
*********************************************************************/
|
||
|
|
||
|
void reportError ( HRESULT hr, NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults )
|
||
|
{
|
||
|
LPTSTR msg = NULL;
|
||
|
|
||
|
MyFormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL, hr, 0, (LPTSTR) &msg, 0, NULL );
|
||
|
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_ERROR_MSG, hr, msg );
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
FUNCTION: reportServiceInfo
|
||
|
|
||
|
PURPOSE: prints out service status and startup information
|
||
|
INPUT: none
|
||
|
|
||
|
RETURNS: none
|
||
|
*********************************************************************/
|
||
|
void reportServiceInfo ( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults )
|
||
|
{
|
||
|
// print status information
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_STATUS );
|
||
|
switch (siIPSecStatus.servStat.dwCurrentState)
|
||
|
{
|
||
|
case SERVICE_RUNNING:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_STARTED );
|
||
|
break;
|
||
|
case SERVICE_STOPPED:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_STOPPED );
|
||
|
break;
|
||
|
case SERVICE_PAUSED:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_PAUSED );
|
||
|
break;
|
||
|
default:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_ADAPTER_UNKNOWN);
|
||
|
break;
|
||
|
}
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_EmptyLine);
|
||
|
|
||
|
// print config information
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_STARTUP );
|
||
|
switch (siIPSecStatus.servConfig.dwStartType)
|
||
|
{
|
||
|
case SERVICE_AUTO_START:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_AUTOMATIC );
|
||
|
break;
|
||
|
case SERVICE_DEMAND_START:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_MANUAL );
|
||
|
break;
|
||
|
case SERVICE_DISABLED:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_IPSEC_PA_DISABLED );
|
||
|
break;
|
||
|
default:
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_ADAPTER_UNKNOWN);
|
||
|
break;
|
||
|
}
|
||
|
AddMessageToList( &pResults->IPSec.lmsgGlobalOutput, Nd_Verbose,
|
||
|
IDS_GLOBAL_EmptyLine);
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
FUNCTION: getIPSecGPO
|
||
|
|
||
|
PURPOSE: returns GPO that is assigning IPSec Policy
|
||
|
INPUT: none
|
||
|
|
||
|
RETURNS: pointer to GROUP_POLICY_OBJECT structure
|
||
|
NULL if policy is not assigned or if GPO information is not retrievable
|
||
|
NOTES: Tested only with domain GPOs
|
||
|
Behaves unpredictably when run for the computer
|
||
|
that does not have active Directory IPSec policy assigned
|
||
|
CALLER is responsible for freeing the memory!
|
||
|
*********************************************************************/
|
||
|
PGROUP_POLICY_OBJECT getIPSecGPO ( )
|
||
|
{
|
||
|
HKEY hKey, hSubKey;
|
||
|
DWORD dwType, dwSize, dwIndex, dwNameSize;
|
||
|
LONG lResult;
|
||
|
TCHAR szName[50];
|
||
|
GUID guid;
|
||
|
PGROUP_POLICY_OBJECT pGPO, pGPOTemp;
|
||
|
PGROUP_POLICY_OBJECT pGPOReturn = NULL;
|
||
|
DWORD dwResult;
|
||
|
|
||
|
//
|
||
|
// Enumerate the extensions
|
||
|
//
|
||
|
|
||
|
lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, GPEXT_KEY, 0, KEY_READ, &hKey);
|
||
|
|
||
|
if (lResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
|
||
|
dwIndex = 0;
|
||
|
dwNameSize = 50;
|
||
|
|
||
|
while ((dwResult = RegEnumKeyEx (hKey, dwIndex++, szName, &dwNameSize, NULL, NULL,
|
||
|
NULL, NULL)) == ERROR_SUCCESS)
|
||
|
{
|
||
|
|
||
|
dwNameSize = 50;
|
||
|
|
||
|
//
|
||
|
// Skip the registry extension since we did it above
|
||
|
//
|
||
|
|
||
|
if (lstrcmpi(TEXT("{35378EAC-683F-11D2-A89A-00C04FBBCFA2}"), szName))
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Get the list of GPOs this extension applied
|
||
|
//
|
||
|
|
||
|
StringToGuid(szName, &guid);
|
||
|
|
||
|
lResult = GetAppliedGPOList (GPO_LIST_FLAG_MACHINE, NULL, NULL,
|
||
|
&guid, &pGPO);
|
||
|
|
||
|
if (lResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
if (pGPO)
|
||
|
{
|
||
|
//
|
||
|
// Get the extension's friendly display name
|
||
|
//
|
||
|
|
||
|
lResult = RegOpenKeyEx (hKey, szName, 0, KEY_READ, &hSubKey);
|
||
|
|
||
|
if (lResult == ERROR_SUCCESS)
|
||
|
{
|
||
|
if (!lstrcmpi(TEXT("{e437bc1c-aa7d-11d2-a382-00c04f991e27}"), szName))
|
||
|
{
|
||
|
// found IPSec
|
||
|
return pGPO;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FreeGPOList(pGPO);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pGPOReturn;
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// StringToGuid()
|
||
|
//
|
||
|
// Purpose: Converts a GUID in string format to a GUID structure
|
||
|
//
|
||
|
// Parameters: szValue - guid in string format
|
||
|
// pGuid - guid structure receiving the guid
|
||
|
//
|
||
|
//
|
||
|
// Return: void
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
void StringToGuid( TCHAR * szValue, GUID * pGuid )
|
||
|
{
|
||
|
TCHAR wc;
|
||
|
INT i;
|
||
|
|
||
|
//
|
||
|
// If the first character is a '{', skip it
|
||
|
//
|
||
|
if ( szValue[0] == TEXT('{') )
|
||
|
szValue++;
|
||
|
|
||
|
//
|
||
|
// Since szValue may be used again, no permanent modification to
|
||
|
// it is be made.
|
||
|
//
|
||
|
|
||
|
wc = szValue[8];
|
||
|
szValue[8] = 0;
|
||
|
pGuid->Data1 = _tcstoul( &szValue[0], 0, 16 );
|
||
|
szValue[8] = wc;
|
||
|
wc = szValue[13];
|
||
|
szValue[13] = 0;
|
||
|
pGuid->Data2 = (USHORT)_tcstoul( &szValue[9], 0, 16 );
|
||
|
szValue[13] = wc;
|
||
|
wc = szValue[18];
|
||
|
szValue[18] = 0;
|
||
|
pGuid->Data3 = (USHORT)_tcstoul( &szValue[14], 0, 16 );
|
||
|
szValue[18] = wc;
|
||
|
|
||
|
wc = szValue[21];
|
||
|
szValue[21] = 0;
|
||
|
pGuid->Data4[0] = (unsigned char)_tcstoul( &szValue[19], 0, 16 );
|
||
|
szValue[21] = wc;
|
||
|
wc = szValue[23];
|
||
|
szValue[23] = 0;
|
||
|
pGuid->Data4[1] = (unsigned char)_tcstoul( &szValue[21], 0, 16 );
|
||
|
szValue[23] = wc;
|
||
|
|
||
|
for ( i = 0; i < 6; i++ )
|
||
|
{
|
||
|
wc = szValue[26+i*2];
|
||
|
szValue[26+i*2] = 0;
|
||
|
pGuid->Data4[2+i] = (unsigned char)_tcstoul( &szValue[24+i*2], 0, 16 );
|
||
|
szValue[26+i*2] = wc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
FUNCTION: getMorePolicyInfo
|
||
|
|
||
|
PURPOSE: gets additional information about currently assigned policy
|
||
|
into piAssignedPolicy global structure
|
||
|
INPUT: none, uses global piAssignedPolicy structure
|
||
|
particularly
|
||
|
iPolicySource
|
||
|
pszPolicyName
|
||
|
pszPolicyPath
|
||
|
fields
|
||
|
|
||
|
RETURNS: HRESULT. Will return ERROR_SUCCESS if everything is fine.
|
||
|
Currently fills pszPolicyDesc and timestamp fields of the global structure
|
||
|
|
||
|
NOTES: This is separate from getPolicyInfo routine for two reasons
|
||
|
a) the information obtained here is optional and error during this particular routine
|
||
|
is not considered fatal
|
||
|
b) the code structure is simpler as this routine is "built on top" of what getPolicyInfo provides
|
||
|
*********************************************************************/
|
||
|
|
||
|
DWORD getMorePolicyInfo ( )
|
||
|
{
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
HKEY hRegKey = NULL;
|
||
|
|
||
|
DWORD dwType; // for RegQueryValueEx
|
||
|
DWORD dwBufLen; // for RegQueryValueEx
|
||
|
DWORD dwValue;
|
||
|
DWORD dwLength = sizeof(DWORD);
|
||
|
|
||
|
PTCHAR* ppszExplodeDN = NULL;
|
||
|
|
||
|
// set some default values
|
||
|
piAssignedPolicy.pszPolicyDesc[0] = 0;
|
||
|
piAssignedPolicy.timestamp = 0;
|
||
|
|
||
|
switch (piAssignedPolicy.iPolicySource)
|
||
|
{
|
||
|
case PS_LOC_POLICY:
|
||
|
// open the key
|
||
|
dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
|
piAssignedPolicy.pszPolicyPath,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hRegKey);
|
||
|
BAIL_ON_WIN32_ERROR(dwError);
|
||
|
|
||
|
// timestamp
|
||
|
dwError = RegQueryValueEx(hRegKey,
|
||
|
pcszIPSecTimestamp,
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
(LPBYTE)&dwValue,
|
||
|
&dwLength);
|
||
|
BAIL_ON_WIN32_ERROR(dwError);
|
||
|
piAssignedPolicy.timestamp = dwValue;
|
||
|
|
||
|
// description
|
||
|
dwBufLen = MAXSTRLEN*sizeof(TCHAR);
|
||
|
dwError = RegQueryValueEx( hRegKey,
|
||
|
pcszIPSecDesc,
|
||
|
NULL,
|
||
|
&dwType, // will be REG_SZ
|
||
|
(LPBYTE) pszBuf,
|
||
|
&dwBufLen);
|
||
|
BAIL_ON_WIN32_ERROR(dwError);
|
||
|
_tcscpy(piAssignedPolicy.pszPolicyDesc, pszBuf);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case PS_DS_POLICY:
|
||
|
// get the policy name from DN
|
||
|
_tcscpy(pszBuf, pcszCacheIPSecKey);
|
||
|
ppszExplodeDN = ldap_explode_dn(piAssignedPolicy.pszPolicyPath, 1);
|
||
|
if (!ppszExplodeDN)
|
||
|
{
|
||
|
goto error;
|
||
|
}
|
||
|
_tcscat(pszBuf, TEXT("\\"));
|
||
|
_tcscat(pszBuf, ppszExplodeDN[0]);
|
||
|
|
||
|
// open the regkey
|
||
|
dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
|
pszBuf,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hRegKey);
|
||
|
BAIL_ON_WIN32_ERROR(dwError);
|
||
|
|
||
|
/* - tomestamp and description are not available yet
|
||
|
// timestamp
|
||
|
dwError = RegQueryValueEx(hRegKey,
|
||
|
pcszIPSecTimestamp,
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
(LPBYTE)&dwValue,
|
||
|
&dwLength);
|
||
|
BAIL_ON_WIN32_ERROR(dwError);
|
||
|
piAssignedPolicy.timestamp = dwValue;
|
||
|
|
||
|
// description
|
||
|
dwBufLen = MAXSTRLEN*sizeof(TCHAR);
|
||
|
dwError = RegQueryValueEx( hRegKey,
|
||
|
pcszIPSecDesc,
|
||
|
NULL,
|
||
|
&dwType, // will be REG_SZ
|
||
|
(LPBYTE) pszBuf,
|
||
|
&dwBufLen);
|
||
|
BAIL_ON_WIN32_ERROR(dwError);
|
||
|
_tcscpy(piAssignedPolicy.pszPolicyDesc, pszBuf);
|
||
|
*/
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
if (hRegKey)
|
||
|
{
|
||
|
RegCloseKey(hRegKey);
|
||
|
}
|
||
|
if (ppszExplodeDN)
|
||
|
{
|
||
|
ldap_value_free(ppszExplodeDN);
|
||
|
}
|
||
|
return dwError;
|
||
|
}
|
||
|
|