/*++ Copyright (c) 1999 Microsoft Corporation Module Name: driver.c Abstract: This module contains all of the code to drive the management of specific filters in the IPSec driver. Author: abhisheV 05-November-1999 Environment User Level: Win32 Revision History: --*/ #include "precomp.h" DWORD SPDStartIPSecDriver( ) /*++ Routine Description: Starts the IPSec Driver service. Arguments: None. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { SC_HANDLE ServiceDatabase = NULL; SC_HANDLE ServiceHandle = NULL; BOOL bStatus = FALSE; DWORD dwError = 0; SERVICE_STATUS IpsecStatus; memset(&IpsecStatus, 0, sizeof(SERVICE_STATUS)); ServiceDatabase = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if (ServiceDatabase == NULL) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } ServiceHandle = OpenService( ServiceDatabase, IPSEC_SERVICE_NAME, SERVICE_START | SERVICE_QUERY_STATUS ); if (ServiceHandle == NULL) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } bStatus = QueryServiceStatus( ServiceHandle, &IpsecStatus ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } if (IpsecStatus.dwCurrentState == SERVICE_STOPPED) { bStatus = StartService( ServiceHandle, 0, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } } error: if (ServiceDatabase != NULL) { CloseServiceHandle(ServiceDatabase); } if (ServiceHandle != NULL) { CloseServiceHandle(ServiceHandle); } return (dwError); } DWORD SPDStopIPSecDriver( ) /*++ Routine Description: Stops the IPSec Driver service. Arguments: None. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { SC_HANDLE ServiceDatabase = NULL; SC_HANDLE ServiceHandle = NULL; BOOL bStatus = FALSE; DWORD dwError = 0; SERVICE_STATUS IpsecStatus; memset(&IpsecStatus, 0, sizeof(SERVICE_STATUS)); ServiceDatabase = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if (ServiceDatabase == NULL) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } ServiceHandle = OpenService( ServiceDatabase, IPSEC_SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS ); if (ServiceHandle == NULL) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } bStatus = QueryServiceStatus( ServiceHandle, &IpsecStatus ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } if (IpsecStatus.dwCurrentState == SERVICE_RUNNING) { bStatus = ControlService( ServiceHandle, SERVICE_CONTROL_STOP, &IpsecStatus ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } } error: if (ServiceDatabase != NULL) { CloseServiceHandle(ServiceDatabase); } if (ServiceHandle != NULL) { CloseServiceHandle(ServiceHandle); } return (dwError); } DWORD SPDOpenIPSecDriver( PHANDLE phIPSecDriver ) /*++ Routine Description: Opens a handle to the IPSec Driver. Arguments: phIPSecDriver - pointer to a handle to the IPSec Driver. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; HANDLE hIPSecDriver = NULL; hIPSecDriver = CreateFile( DEVICE_NAME, // File name. GENERIC_READ | GENERIC_WRITE, // Access mode. 0, // Share mode. NULL, // Security attributes. OPEN_EXISTING, // How to create. 0, // File attributes. NULL // Handle to file. ); if (hIPSecDriver == INVALID_HANDLE_VALUE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } *phIPSecDriver = hIPSecDriver; return (dwError); error: *phIPSecDriver = INVALID_HANDLE_VALUE; return (dwError); } VOID SPDCloseIPSecDriver( HANDLE hIPSecDriver ) /*++ Routine Description: Closes the handle to the IPSec Driver. Arguments: hIPSecDriver - handle to the IPSec Driver to close. Return Value: None. --*/ { if (hIPSecDriver) { CloseHandle(hIPSecDriver); } } DWORD InsertTransportFiltersIntoIPSec( PINITXSFILTER pSpecificFilters ) /*++ Routine Description: Insert a list of specific filters into the IPSec Driver. Arguments: pSpecificFilters - list of filters to insert. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; HANDLE hIPSecDriver = NULL; LPBYTE pInBuffer = NULL; DWORD dwInBufferSize = 0; BOOL bStatus = FALSE; LPBYTE pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; DWORD dwNumFilters = 0; PIPSEC_FILTER_INFO pInternalFilters = NULL; LPBYTE pTemp = NULL; DWORD i = 0; if (!pSpecificFilters) { return (dwError); } dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); dwError = WrapTransportFilters( pSpecificFilters, &pInternalFilters, &dwNumFilters ); BAIL_ON_WIN32_ERROR(dwError); dwInBufferSize = sizeof(DWORD) + sizeof(IPSEC_FILTER_INFO)*dwNumFilters; dwError = AllocateSPDMemory( dwInBufferSize, &pInBuffer ); BAIL_ON_WIN32_ERROR(dwError); pTemp = pInBuffer; memcpy(pTemp, &dwNumFilters, sizeof(DWORD)); pTemp += sizeof(DWORD); for (i = 0 ; i < dwNumFilters; i++) { memcpy(pTemp, &(pInternalFilters[i]), sizeof(IPSEC_FILTER_INFO)); pTemp += sizeof(IPSEC_FILTER_INFO); } bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_ADD_FILTER, pInBuffer, dwInBufferSize, pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } error: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } if (pInternalFilters) { FreeSPDMemory(pInternalFilters); } if (pInBuffer) { FreeSPDMemory(pInBuffer); } if (pOutBuffer) { LocalFree(pOutBuffer); } return (dwError); } DWORD DeleteTransportFiltersFromIPSec( PINITXSFILTER pSpecificFilters ) /*++ Routine Description: Delete a list of filters from the IPSec Driver. Arguments: pSpecificFilters - list of filters to delete. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; HANDLE hIPSecDriver = NULL; LPBYTE pInBuffer = NULL; DWORD dwInBufferSize = 0; BOOL bStatus = FALSE; LPBYTE pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; DWORD dwNumFilters = 0; PIPSEC_FILTER_INFO pInternalFilters = NULL; LPBYTE pTemp = NULL; DWORD i = 0; if (!pSpecificFilters) { return (dwError); } dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); dwError = WrapTransportFilters( pSpecificFilters, &pInternalFilters, &dwNumFilters ); BAIL_ON_WIN32_ERROR(dwError); dwInBufferSize = sizeof(DWORD) + sizeof(IPSEC_FILTER_INFO)*dwNumFilters; dwError = AllocateSPDMemory( dwInBufferSize, &pInBuffer ); BAIL_ON_WIN32_ERROR(dwError); pTemp = pInBuffer; memcpy(pTemp, &dwNumFilters, sizeof(DWORD)); pTemp += sizeof(DWORD); for (i = 0 ; i < dwNumFilters; i++) { memcpy(pTemp, &(pInternalFilters[i]), sizeof(IPSEC_FILTER_INFO)); pTemp += sizeof(IPSEC_FILTER_INFO); } bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_DELETE_FILTER, pInBuffer, dwInBufferSize, pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } error: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } if (pInternalFilters) { FreeSPDMemory(pInternalFilters); } if (pInBuffer) { FreeSPDMemory(pInBuffer); } if (pOutBuffer) { LocalFree(pOutBuffer); } return (dwError); } DWORD WrapTransportFilters( PINITXSFILTER pSpecificFilters, PIPSEC_FILTER_INFO * ppInternalFilters, PDWORD pdwNumFilters ) /*++ Routine Description: Transforms a list of specific transport filters to an equivalent list of filters acceptable to the IPSec Driver. Arguments: pSpecificFilters - list of filters to convert. ppInternalFilters - list of transformed filters. pdwNumFilters - count of the filters in the transformed list. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; PINITXSFILTER pTempFilter = NULL; PIPSEC_FILTER_INFO pInternalFilters = NULL; DWORD dwNumFilters = 0; DWORD i = 0; // // At this point, there's atleast one filter in the // specific filter list. // pTempFilter = pSpecificFilters; while(pTempFilter) { pTempFilter = pTempFilter->pNext; dwNumFilters++; } dwError = AllocateSPDMemory( sizeof(IPSEC_FILTER_INFO)*dwNumFilters, &pInternalFilters ); BAIL_ON_WIN32_ERROR(dwError); pTempFilter = pSpecificFilters; while(pTempFilter) { FormIPSecTransportFilter( pTempFilter, &(pInternalFilters[i]) ); pTempFilter = pTempFilter->pNext; i++; } *ppInternalFilters = pInternalFilters; *pdwNumFilters = dwNumFilters; return (dwError); error: *ppInternalFilters = NULL; *pdwNumFilters = 0; return (dwError); } VOID FormIPSecTransportFilter( PINITXSFILTER pSpecificFilter, PIPSEC_FILTER_INFO pIpsecFilter ) /*++ Routine Description: Transforms a specific transport filter to an equivalent filter acceptable to the IPSec Driver. Arguments: pSpecificFilter - filter to convert. pIpsecFilter - transformed filter. Return Value: NONE. --*/ { memcpy( &(pIpsecFilter->FilterId), &(pSpecificFilter->gParentID), sizeof(GUID) ); memcpy( &(pIpsecFilter->PolicyId), &(pSpecificFilter->gPolicyID), sizeof(GUID) ); pIpsecFilter->Index = pSpecificFilter->dwWeight; pIpsecFilter->AssociatedFilter.SrcAddr = pSpecificFilter->SrcAddr.uIpAddr; pIpsecFilter->AssociatedFilter.SrcMask = pSpecificFilter->SrcAddr.uSubNetMask; pIpsecFilter->AssociatedFilter.DestAddr = pSpecificFilter->DesAddr.uIpAddr; pIpsecFilter->AssociatedFilter.DestMask = pSpecificFilter->DesAddr.uSubNetMask; pIpsecFilter->AssociatedFilter.Protocol = pSpecificFilter->Protocol.dwProtocol; pIpsecFilter->AssociatedFilter.SrcPort = pSpecificFilter->SrcPort.wPort; pIpsecFilter->AssociatedFilter.DestPort = pSpecificFilter->DesPort.wPort; pIpsecFilter->AssociatedFilter.TunnelFilter = FALSE; pIpsecFilter->AssociatedFilter.TunnelAddr = 0; pIpsecFilter->AssociatedFilter.Flags = 0; if (pSpecificFilter->dwDirection == FILTER_DIRECTION_INBOUND) { pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_INBOUND; switch (pSpecificFilter->InboundFilterFlag) { case PASS_THRU: pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_PASS_THRU; break; case BLOCKING: pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_DROP; break; default: break; } } else { pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_OUTBOUND; switch (pSpecificFilter->OutboundFilterFlag) { case PASS_THRU: pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_PASS_THRU; break; case BLOCKING: pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_DROP; break; default: break; } } } DWORD QueryIPSecStatistics( LPWSTR pServerName, PIPSEC_STATISTICS * ppIpsecStatistics ) { DWORD dwError = 0; PIPSEC_STATISTICS pIpsecStatistics = NULL; ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); LEAVE_SPD_SECTION(); BAIL_ON_WIN32_ERROR(dwError); dwError = QueryDriverForIpsecStats( &pIpsecStatistics ); BAIL_ON_WIN32_ERROR(dwError); *ppIpsecStatistics = pIpsecStatistics; cleanup: return (dwError); error: *ppIpsecStatistics = NULL; goto cleanup; } DWORD QueryDriverForIpsecStats( PIPSEC_QUERY_STATS * ppQueryStats ) { DWORD dwError = 0; PIPSEC_QUERY_STATS pQueryStats = NULL; HANDLE hIPSecDriver = NULL; LPBYTE pInBuffer = NULL; DWORD dwInBufferSize = 0; BOOL bStatus = FALSE; LPBYTE pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; dwError = SPDApiBufferAllocate( sizeof(IPSEC_QUERY_STATS), &pQueryStats ); BAIL_ON_WIN32_ERROR(dwError); dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); pInBuffer = (LPBYTE) pQueryStats; dwInBufferSize = sizeof(IPSEC_QUERY_STATS); pOutBuffer = (LPBYTE) pQueryStats; dwOutBufferSize = sizeof(IPSEC_QUERY_STATS); dwBytesReturned = dwOutBufferSize; bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_QUERY_STATS, pInBuffer, dwInBufferSize, pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } *ppQueryStats = pQueryStats; cleanup: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } return (dwError); error: if (pQueryStats) { SPDApiBufferFree(pQueryStats); } *ppQueryStats = NULL; goto cleanup; } DWORD EnumQMSAs( LPWSTR pServerName, PIPSEC_QM_SA pQMSATemplate, PIPSEC_QM_SA * ppQMSAs, DWORD dwPreferredNumEntries, LPDWORD pdwNumQMSAs, LPDWORD pdwNumTotalQMSAs, LPDWORD pdwResumeHandle, DWORD dwFlags ) { DWORD dwError = 0; DWORD dwResumeHandle = 0; DWORD dwNumToEnum = 0; DWORD dwNumTotalQMSAs = 0; PIPSEC_ENUM_SAS pIpsecEnumSAs = NULL; PIPSEC_SA_INFO pInfo = NULL; DWORD i = 0; DWORD dwNumQMSAs = 0; PIPSEC_QM_SA pQMSAs = NULL; PIPSEC_SA_INFO pTemp = NULL; PIPSEC_QM_SA pTempQMSA = NULL; dwResumeHandle = *pdwResumeHandle; if (!dwPreferredNumEntries || (dwPreferredNumEntries > MAX_QMSA_ENUM_COUNT)) { dwNumToEnum = MAX_QMSA_ENUM_COUNT; } else { dwNumToEnum = dwPreferredNumEntries; } ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); LEAVE_SPD_SECTION(); BAIL_ON_WIN32_ERROR(dwError); dwError = IpsecEnumSAs( &dwNumTotalQMSAs, &pIpsecEnumSAs ); BAIL_ON_WIN32_ERROR(dwError); if (dwNumTotalQMSAs <= dwResumeHandle) { dwError = ERROR_NO_DATA; BAIL_ON_WIN32_ERROR(dwError); } pInfo = pIpsecEnumSAs->pInfo; for (i = 0; i < dwResumeHandle; i++) { pInfo++; } dwNumQMSAs = dwNumTotalQMSAs - dwResumeHandle; if (dwNumQMSAs > dwNumToEnum) { dwNumQMSAs = dwNumToEnum; } dwError = SPDApiBufferAllocate( sizeof(IPSEC_QM_SA)*dwNumQMSAs, &pQMSAs ); BAIL_ON_WIN32_ERROR(dwError); pTemp = pInfo; pTempQMSA = pQMSAs; for (i = 0; i < dwNumQMSAs; i++) { dwError = CopyQMSA( pTemp, pTempQMSA ); BAIL_ON_WIN32_ERROR(dwError); pTemp++; pTempQMSA++; } *ppQMSAs = pQMSAs; *pdwResumeHandle = dwResumeHandle + dwNumQMSAs; *pdwNumQMSAs = dwNumQMSAs; *pdwNumTotalQMSAs = dwNumTotalQMSAs; cleanup: if (pIpsecEnumSAs) { FreeSPDMem(pIpsecEnumSAs); } return (dwError); error: if (pQMSAs) { FreeQMSAs( i, pQMSAs ); } *ppQMSAs = NULL; *pdwResumeHandle = dwResumeHandle; *pdwNumQMSAs = 0; *pdwNumTotalQMSAs = 0; goto cleanup; } DWORD IpsecEnumSAs( PDWORD pdwNumberOfSAs, PIPSEC_ENUM_SAS * ppIpsecEnumSAs ) { DWORD dwError = 0; DWORD dwNumberOfSAs = 0; PIPSEC_ENUM_SAS pIpsecEnumSAs = NULL; HANDLE hIPSecDriver = NULL; BOOL bStatus = FALSE; PIPSEC_ENUM_SAS pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); // // The first call passes in a return buffer of size IPSEC_ENUM_SAS. // The idea here is to determine the number of SAs and then pass // a second buffer with the correct size. // dwOutBufferSize = sizeof(IPSEC_ENUM_SAS); pOutBuffer = (PIPSEC_ENUM_SAS) AllocSPDMem( sizeof(IPSEC_ENUM_SAS) ); if (!pOutBuffer) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32_ERROR(dwError); } memset(pOutBuffer, 0, dwOutBufferSize); dwBytesReturned = dwOutBufferSize; bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_ENUM_SAS, NULL, 0, (PVOID) pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); // // The error code here should be either ERROR_BUFFER_OVERFLOW // or ERROR_MORE_DATA or ERROR_SUCCESS. // if (!bStatus) { dwError = GetLastError(); } else { dwError = ERROR_SUCCESS; } while (dwError == ERROR_BUFFER_OVERFLOW || dwError == ERROR_MORE_DATA) { // // Determine the number of SAs that the driver currently has. // pIpsecEnumSAs = (PIPSEC_ENUM_SAS) pOutBuffer; dwNumberOfSAs = pIpsecEnumSAs->NumEntriesPresent; if (dwNumberOfSAs == 0) { dwError = ERROR_NO_DATA; BAIL_ON_WIN32_ERROR(dwError); } if (pOutBuffer) { FreeSPDMem(pOutBuffer); pOutBuffer = NULL; } dwOutBufferSize = sizeof(IPSEC_ENUM_SAS) + (dwNumberOfSAs -1)*sizeof(IPSEC_SA_INFO); pOutBuffer = (PIPSEC_ENUM_SAS) AllocSPDMem( dwOutBufferSize ); if (!pOutBuffer) { dwError = ERROR_OUTOFMEMORY; BAIL_ON_WIN32_ERROR(dwError); } memset(pOutBuffer, 0, dwOutBufferSize); dwBytesReturned = dwOutBufferSize; bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_ENUM_SAS, NULL, 0, (PVOID) pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (!bStatus) { dwError = GetLastError(); } else { dwError = ERROR_SUCCESS; } } pIpsecEnumSAs = (PIPSEC_ENUM_SAS) pOutBuffer; dwNumberOfSAs = pIpsecEnumSAs->NumEntries; if (dwNumberOfSAs == 0) { dwError = ERROR_NO_DATA; BAIL_ON_WIN32_ERROR(dwError); } *pdwNumberOfSAs = dwNumberOfSAs; *ppIpsecEnumSAs = pIpsecEnumSAs; cleanup: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } return (dwError); error: *pdwNumberOfSAs = 0; *ppIpsecEnumSAs = NULL; if (pOutBuffer) { FreeSPDMem(pOutBuffer); } goto cleanup; } DWORD CopyQMSA( PIPSEC_SA_INFO pInfo, PIPSEC_QM_SA pQMSA ) { DWORD dwError = 0; memcpy( &(pQMSA->gQMPolicyID), &(pInfo->PolicyId), sizeof(GUID) ); memcpy( &(pQMSA->gQMFilterID), &(pInfo->FilterId), sizeof(GUID) ); CopyQMSAOffer( pInfo, &(pQMSA->SelectedQMOffer) ); CopyQMSAFilter( pInfo->InboundTunnelAddr, &(pInfo->AssociatedFilter), &(pQMSA->IpsecQMFilter) ); CopyQMSAMMSpi( pInfo->CookiePair, &(pQMSA->MMSpi) ); return (dwError); } VOID CopyQMSAOffer( PIPSEC_SA_INFO pInfo, PIPSEC_QM_OFFER pOffer ) { DWORD i = 0; DWORD j = 0; DWORD k = 0; pOffer->Lifetime.uKeyExpirationTime = pInfo->Lifetime.KeyExpirationTime; pOffer->Lifetime.uKeyExpirationKBytes = pInfo->Lifetime.KeyExpirationBytes; pOffer->dwFlags = 0; pOffer->dwPFSGroup = pInfo->dwQMPFSGroup; if ((pOffer->dwPFSGroup != PFS_GROUP_1) && (pOffer->dwPFSGroup != PFS_GROUP_2) && (pOffer->dwPFSGroup != PFS_GROUP_MM)) { pOffer->dwPFSGroup = PFS_GROUP_NONE; pOffer->bPFSRequired = FALSE; } else { pOffer->bPFSRequired = TRUE; } i = 0; for (j = 0; (j < pInfo->NumOps) && (i < QM_MAX_ALGOS) ; j++) { switch (pInfo->Operation[j]) { case Auth: switch (pInfo->AlgoInfo[j].IntegrityAlgo.algoIdentifier) { case IPSEC_AH_MD5: pOffer->Algos[i].uAlgoIdentifier = IPSEC_DOI_AH_MD5; break; case IPSEC_AH_SHA: pOffer->Algos[i].uAlgoIdentifier = IPSEC_DOI_AH_SHA1; break; default: pOffer->Algos[i].uAlgoIdentifier = IPSEC_DOI_AH_NONE; break; } pOffer->Algos[i].uSecAlgoIdentifier = HMAC_AH_NONE; pOffer->Algos[i].Operation = AUTHENTICATION; pOffer->Algos[i].uAlgoKeyLen = pInfo->AlgoInfo[j].IntegrityAlgo.algoKeylen; pOffer->Algos[i].uAlgoRounds = pInfo->AlgoInfo[j].IntegrityAlgo.algoRounds; pOffer->Algos[i].MySpi = pInfo->InboundSPI[j]; pOffer->Algos[i].PeerSpi = pInfo->OutboundSPI[j]; i++; break; case Encrypt: switch (pInfo->AlgoInfo[j].ConfAlgo.algoIdentifier) { case IPSEC_ESP_DES: pOffer->Algos[i].uAlgoIdentifier = IPSEC_DOI_ESP_DES; break; case IPSEC_ESP_DES_40: pOffer->Algos[i].uAlgoIdentifier = IPSEC_DOI_ESP_DES; break; case IPSEC_ESP_3_DES: pOffer->Algos[i].uAlgoIdentifier = IPSEC_DOI_ESP_3_DES; break; default: pOffer->Algos[i].uAlgoIdentifier = IPSEC_DOI_ESP_NONE; break; } switch (pInfo->AlgoInfo[j].IntegrityAlgo.algoIdentifier) { case IPSEC_AH_MD5: pOffer->Algos[i].uSecAlgoIdentifier = HMAC_AH_MD5; break; case IPSEC_AH_SHA: pOffer->Algos[i].uSecAlgoIdentifier = HMAC_AH_SHA1; break; default: pOffer->Algos[i].uSecAlgoIdentifier = HMAC_AH_NONE; break; } pOffer->Algos[i].Operation = ENCRYPTION; pOffer->Algos[i].uAlgoKeyLen = pInfo->AlgoInfo[j].ConfAlgo.algoKeylen; pOffer->Algos[i].uAlgoRounds = pInfo->AlgoInfo[j].ConfAlgo.algoRounds; pOffer->Algos[i].MySpi = pInfo->InboundSPI[j]; pOffer->Algos[i].PeerSpi = pInfo->OutboundSPI[j]; i++; break; case None: pOffer->Algos[i].Operation = NONE; pOffer->Algos[i].uAlgoIdentifier = IPSEC_DOI_ESP_NONE; pOffer->Algos[i].uSecAlgoIdentifier = HMAC_AH_NONE; pOffer->Algos[i].uAlgoKeyLen = 0; pOffer->Algos[i].uAlgoRounds = 0; pOffer->Algos[i].MySpi = pInfo->InboundSPI[j]; pOffer->Algos[i].PeerSpi = pInfo->OutboundSPI[j]; i++; break; case Compress: default: break; } } for (k = i; k < QM_MAX_ALGOS; k++) { memset(&(pOffer->Algos[k]), 0, sizeof(IPSEC_QM_ALGO)); } pOffer->dwNumAlgos = i; return; } VOID CopyQMSAFilter( IPAddr MyTunnelEndpt, PIPSEC_FILTER pIpsecFilter, PIPSEC_QM_FILTER pIpsecQMFilter ) { if (pIpsecFilter->TunnelFilter) { pIpsecQMFilter->QMFilterType = QM_TUNNEL_FILTER; } else { pIpsecQMFilter->QMFilterType = QM_TRANSPORT_FILTER; } PASetAddress( pIpsecFilter->SrcMask, pIpsecFilter->SrcAddr, &(pIpsecQMFilter->SrcAddr) ); PASetAddress( pIpsecFilter->DestMask, pIpsecFilter->DestAddr, &(pIpsecQMFilter->DesAddr) ); pIpsecQMFilter->Protocol.ProtocolType = PROTOCOL_UNIQUE; pIpsecQMFilter->Protocol.dwProtocol = pIpsecFilter->Protocol; pIpsecQMFilter->SrcPort.PortType = PORT_UNIQUE; pIpsecQMFilter->SrcPort.wPort = ntohs(pIpsecFilter->SrcPort); pIpsecQMFilter->DesPort.PortType = PORT_UNIQUE; pIpsecQMFilter->DesPort.wPort = ntohs(pIpsecFilter->DestPort); if (pIpsecFilter->TunnelFilter) { PASetTunnelAddress( MyTunnelEndpt, &(pIpsecQMFilter->MyTunnelEndpt) ); PASetTunnelAddress( pIpsecFilter->TunnelAddr, &(pIpsecQMFilter->PeerTunnelEndpt) ); } else { PASetAddress( SUBNET_MASK_ANY, SUBNET_ADDRESS_ANY, &(pIpsecQMFilter->MyTunnelEndpt) ); PASetAddress( SUBNET_MASK_ANY, SUBNET_ADDRESS_ANY, &(pIpsecQMFilter->PeerTunnelEndpt) ); } pIpsecQMFilter->dwFlags = 0; if ((pIpsecFilter->Flags) & FILTER_FLAGS_INBOUND) { pIpsecQMFilter->dwFlags |= FILTER_DIRECTION_INBOUND; } else { pIpsecQMFilter->dwFlags |= FILTER_DIRECTION_OUTBOUND; } if ((pIpsecFilter->Flags) & FILTER_FLAGS_PASS_THRU) { pIpsecQMFilter->dwFlags |= FILTER_NATURE_PASS_THRU; } else if ((pIpsecFilter->Flags) & FILTER_FLAGS_DROP) { pIpsecQMFilter->dwFlags |= FILTER_NATURE_BLOCKING; } else { pIpsecQMFilter->dwFlags |= 0; } return; } VOID CopyQMSAMMSpi( IKE_COOKIE_PAIR CookiePair, PIKE_COOKIE_PAIR pMMSpi ) { pMMSpi->Initiator = CookiePair.Initiator; pMMSpi->Responder = CookiePair.Responder; return; } VOID FreeQMSAs( DWORD dwCnt, PIPSEC_QM_SA pQMSAs ) { if (pQMSAs) { SPDApiBufferFree(pQMSAs); } } DWORD InsertTunnelFiltersIntoIPSec( PINITNSFILTER pSpecificFilters ) /*++ Routine Description: Insert a list of specific filters into the IPSec Driver. Arguments: pSpecificFilters - list of filters to insert. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; HANDLE hIPSecDriver = NULL; LPBYTE pInBuffer = NULL; DWORD dwInBufferSize = 0; BOOL bStatus = FALSE; LPBYTE pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; DWORD dwNumFilters = 0; PIPSEC_FILTER_INFO pInternalFilters = NULL; LPBYTE pTemp = NULL; DWORD i = 0; if (!pSpecificFilters) { return (dwError); } dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); dwError = WrapTunnelFilters( pSpecificFilters, &pInternalFilters, &dwNumFilters ); BAIL_ON_WIN32_ERROR(dwError); dwInBufferSize = sizeof(DWORD) + sizeof(IPSEC_FILTER_INFO)*dwNumFilters; dwError = AllocateSPDMemory( dwInBufferSize, &pInBuffer ); BAIL_ON_WIN32_ERROR(dwError); pTemp = pInBuffer; memcpy(pTemp, &dwNumFilters, sizeof(DWORD)); pTemp += sizeof(DWORD); for (i = 0 ; i < dwNumFilters; i++) { memcpy(pTemp, &(pInternalFilters[i]), sizeof(IPSEC_FILTER_INFO)); pTemp += sizeof(IPSEC_FILTER_INFO); } bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_ADD_FILTER, pInBuffer, dwInBufferSize, pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } error: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } if (pInternalFilters) { FreeSPDMemory(pInternalFilters); } if (pInBuffer) { FreeSPDMemory(pInBuffer); } if (pOutBuffer) { LocalFree(pOutBuffer); } return (dwError); } DWORD DeleteTunnelFiltersFromIPSec( PINITNSFILTER pSpecificFilters ) /*++ Routine Description: Delete a list of filters from the IPSec Driver. Arguments: pSpecificFilters - list of filters to delete. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; HANDLE hIPSecDriver = NULL; LPBYTE pInBuffer = NULL; DWORD dwInBufferSize = 0; BOOL bStatus = FALSE; LPBYTE pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; DWORD dwNumFilters = 0; PIPSEC_FILTER_INFO pInternalFilters = NULL; LPBYTE pTemp = NULL; DWORD i = 0; if (!pSpecificFilters) { return (dwError); } dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); dwError = WrapTunnelFilters( pSpecificFilters, &pInternalFilters, &dwNumFilters ); BAIL_ON_WIN32_ERROR(dwError); dwInBufferSize = sizeof(DWORD) + sizeof(IPSEC_FILTER_INFO)*dwNumFilters; dwError = AllocateSPDMemory( dwInBufferSize, &pInBuffer ); BAIL_ON_WIN32_ERROR(dwError); pTemp = pInBuffer; memcpy(pTemp, &dwNumFilters, sizeof(DWORD)); pTemp += sizeof(DWORD); for (i = 0 ; i < dwNumFilters; i++) { memcpy(pTemp, &(pInternalFilters[i]), sizeof(IPSEC_FILTER_INFO)); pTemp += sizeof(IPSEC_FILTER_INFO); } bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_DELETE_FILTER, pInBuffer, dwInBufferSize, pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } error: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } if (pInternalFilters) { FreeSPDMemory(pInternalFilters); } if (pInBuffer) { FreeSPDMemory(pInBuffer); } if (pOutBuffer) { LocalFree(pOutBuffer); } return (dwError); } DWORD WrapTunnelFilters( PINITNSFILTER pSpecificFilters, PIPSEC_FILTER_INFO * ppInternalFilters, PDWORD pdwNumFilters ) /*++ Routine Description: Transforms a list of specific tunnel filters to an equivalent list of filters acceptable to the IPSec Driver. Arguments: pSpecificFilters - list of filters to convert. ppInternalFilters - list of transformed filters. pdwNumFilters - count of the filters in the transformed list. Return Value: ERROR_SUCCESS - Success. Win32 Error - Failure. --*/ { DWORD dwError = 0; PINITNSFILTER pTempFilter = NULL; PIPSEC_FILTER_INFO pInternalFilters = NULL; DWORD dwNumFilters = 0; DWORD i = 0; // // At this point, there's atleast one filter in the // specific filter list. // pTempFilter = pSpecificFilters; while(pTempFilter) { pTempFilter = pTempFilter->pNext; dwNumFilters++; } dwError = AllocateSPDMemory( sizeof(IPSEC_FILTER_INFO)*dwNumFilters, &pInternalFilters ); BAIL_ON_WIN32_ERROR(dwError); pTempFilter = pSpecificFilters; while(pTempFilter) { FormIPSecTunnelFilter( pTempFilter, &(pInternalFilters[i]) ); pTempFilter = pTempFilter->pNext; i++; } *ppInternalFilters = pInternalFilters; *pdwNumFilters = dwNumFilters; return (dwError); error: *ppInternalFilters = NULL; *pdwNumFilters = 0; return (dwError); } VOID FormIPSecTunnelFilter( PINITNSFILTER pSpecificFilter, PIPSEC_FILTER_INFO pIpsecFilter ) /*++ Routine Description: Transforms a specific tunnel filter to an equivalent filter acceptable to the IPSec Driver. Arguments: pSpecificFilter - filter to convert. pIpsecFilter - transformed filter. Return Value: NONE. --*/ { memcpy( &(pIpsecFilter->FilterId), &(pSpecificFilter->gParentID), sizeof(GUID) ); memcpy( &(pIpsecFilter->PolicyId), &(pSpecificFilter->gPolicyID), sizeof(GUID) ); pIpsecFilter->Index = pSpecificFilter->dwWeight; pIpsecFilter->AssociatedFilter.SrcAddr = pSpecificFilter->SrcAddr.uIpAddr; pIpsecFilter->AssociatedFilter.SrcMask = pSpecificFilter->SrcAddr.uSubNetMask; pIpsecFilter->AssociatedFilter.DestAddr = pSpecificFilter->DesAddr.uIpAddr; pIpsecFilter->AssociatedFilter.DestMask = pSpecificFilter->DesAddr.uSubNetMask; pIpsecFilter->AssociatedFilter.Protocol = pSpecificFilter->Protocol.dwProtocol; pIpsecFilter->AssociatedFilter.SrcPort = pSpecificFilter->SrcPort.wPort; pIpsecFilter->AssociatedFilter.DestPort = pSpecificFilter->DesPort.wPort; pIpsecFilter->AssociatedFilter.TunnelFilter = TRUE; pIpsecFilter->AssociatedFilter.TunnelAddr = pSpecificFilter->DesTunnelAddr.uIpAddr; pIpsecFilter->AssociatedFilter.Flags = 0; if (pSpecificFilter->dwDirection == FILTER_DIRECTION_INBOUND) { pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_INBOUND; switch (pSpecificFilter->InboundFilterFlag) { case PASS_THRU: pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_PASS_THRU; break; case BLOCKING: pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_DROP; break; default: break; } } else { pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_OUTBOUND; switch (pSpecificFilter->OutboundFilterFlag) { case PASS_THRU: pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_PASS_THRU; break; case BLOCKING: pIpsecFilter->AssociatedFilter.Flags |= FILTER_FLAGS_DROP; break; default: break; } } } DWORD SPDSetIPSecDriverOpMode( DWORD dwOpMode ) { DWORD dwError = 0; HANDLE hIPSecDriver = NULL; PIPSEC_SET_OPERATION_MODE pIpsecSetOpMode = NULL; LPBYTE pInBuffer = NULL; DWORD dwInBufferSize = 0; LPBYTE pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; BOOL bStatus = FALSE; dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); dwError = AllocateSPDMemory( sizeof(IPSEC_SET_OPERATION_MODE), &pIpsecSetOpMode ); BAIL_ON_WIN32_ERROR(dwError); pIpsecSetOpMode->OperationMode = (OPERATION_MODE) dwOpMode; pInBuffer = (LPBYTE) pIpsecSetOpMode; dwInBufferSize = sizeof(IPSEC_SET_OPERATION_MODE); pOutBuffer = (LPBYTE) pIpsecSetOpMode; dwOutBufferSize = sizeof(IPSEC_SET_OPERATION_MODE); dwBytesReturned = dwOutBufferSize; bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_SET_OPERATION_MODE, pInBuffer, dwInBufferSize, pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } error: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } if (pIpsecSetOpMode) { FreeSPDMemory(pIpsecSetOpMode); } return (dwError); } DWORD IPSecDeleteQMSAs( LPWSTR pServerName, PIPSEC_QM_SA pIpsecQMSA, DWORD dwFlags ) { DWORD dwError = ERROR_SUCCESS; HANDLE hIPSecDriver = NULL; IPSEC_DELETE_SA IpsecDeleteSA; LPBYTE pInBuffer = NULL; DWORD dwInBufferSize = 0; LPBYTE pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; BOOL bStatus = FALSE; ENTER_SPD_SECTION(); dwError = ValidateSecurity( SPD_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL ); LEAVE_SPD_SECTION(); BAIL_ON_WIN32_ERROR(dwError); dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); memcpy( &IpsecDeleteSA.SATemplate, pIpsecQMSA, sizeof(IPSEC_QM_SA) ); pInBuffer = (LPBYTE) &IpsecDeleteSA; dwInBufferSize = sizeof(IPSEC_DELETE_SA); pOutBuffer = (LPBYTE) &IpsecDeleteSA; dwOutBufferSize = sizeof(IPSEC_DELETE_SA); dwBytesReturned = dwOutBufferSize; bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_DELETE_SA, pInBuffer, dwInBufferSize, pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } error: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } return (dwError); } DWORD SPDRegisterIPSecDriverProtocols( DWORD dwRegisterMode ) { DWORD dwError = 0; HANDLE hIPSecDriver = NULL; PIPSEC_REGISTER_PROTOCOL pIpsecRegisterProtocol = NULL; LPBYTE pInBuffer = NULL; DWORD dwInBufferSize = 0; LPBYTE pOutBuffer = NULL; DWORD dwOutBufferSize = 0; DWORD dwBytesReturned = 0; BOOL bStatus = FALSE; dwError = SPDOpenIPSecDriver( &hIPSecDriver ); BAIL_ON_WIN32_ERROR(dwError); dwError = AllocateSPDMemory( sizeof(IPSEC_REGISTER_PROTOCOL), &pIpsecRegisterProtocol ); BAIL_ON_WIN32_ERROR(dwError); pIpsecRegisterProtocol->RegisterProtocol = (REGISTER_PROTOCOL) dwRegisterMode; pInBuffer = (LPBYTE) pIpsecRegisterProtocol; dwInBufferSize = sizeof(IPSEC_REGISTER_PROTOCOL); pOutBuffer = (LPBYTE) pIpsecRegisterProtocol; dwOutBufferSize = sizeof(IPSEC_REGISTER_PROTOCOL); dwBytesReturned = dwOutBufferSize; bStatus = DeviceIoControl( hIPSecDriver, IOCTL_IPSEC_REGISTER_PROTOCOL, pInBuffer, dwInBufferSize, pOutBuffer, dwOutBufferSize, &dwBytesReturned, NULL ); if (bStatus == FALSE) { dwError = GetLastError(); BAIL_ON_WIN32_ERROR(dwError); } error: if (hIPSecDriver != INVALID_HANDLE_VALUE) { SPDCloseIPSecDriver(hIPSecDriver); } if (pIpsecRegisterProtocol) { FreeSPDMemory(pIpsecRegisterProtocol); } return (dwError); }