Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

584 lines
13 KiB

#include "precomp.h"
#pragma hdrstop
NTSTATUS
IPSecGetSPI(
PIPSEC_GET_SPI pIpsecGetSPI
)
/*++
Routine Description:
This routine returns the SPI.
Arguments:
pIpsecGetSPI - Pointer to the ipsec get spi structure.
Return Value:
NTSTATUS - The status code from this routine.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIPSEC_ACQUIRE_CONTEXT pIpsecAcquireCtx = NULL;
pIpsecAcquireCtx = (PIPSEC_ACQUIRE_CONTEXT) pIpsecGetSPI->Context;
//
// If context was passed in, then there's a larval SA already setup.
// This is the case for the initiator.
//
if (pIpsecAcquireCtx) {
ntStatus = IPSecInitiatorGetSPI(
pIpsecGetSPI
);
}
else {
ntStatus = IPSecResponderGetSPI(
pIpsecGetSPI
);
}
return (ntStatus);
}
NTSTATUS
IPSecInitiatorGetSPI(
PIPSEC_GET_SPI pIpsecGetSPI
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIPSEC_ACQUIRE_CONTEXT pIpsecAcquireCtx = NULL;
KIRQL kIrql;
pIpsecAcquireCtx = (PIPSEC_ACQUIRE_CONTEXT) pIpsecGetSPI->Context;
//
// Sanity check the incoming context to see if it is actually
// an SA block.
//
ACQUIRE_LOCK(&g_ipsec.LarvalListLock, &kIrql);
if (!NT_SUCCESS(IPSecValidateHandle(pIpsecAcquireCtx, STATE_SA_LARVAL))) {
ntStatus = STATUS_INVALID_PARAMETER;
BAIL_ON_LOCK_NTSTATUS_ERROR(ntStatus);
}
pIpsecGetSPI->SPI = pIpsecAcquireCtx->pSA->sa_SPI;
pIpsecAcquireCtx->pSA->sa_Flags |= FLAGS_SA_INITIATOR;
ntStatus = STATUS_SUCCESS;
lock:
RELEASE_LOCK(&g_ipsec.LarvalListLock, kIrql);
return (ntStatus);
}
NTSTATUS
IPSecResponderGetSPI(
PIPSEC_GET_SPI pIpsecGetSPI
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
KIRQL kIrql;
PSA_TABLE_ENTRY pInboundSA = NULL;
ULARGE_INTEGER uliSrcDstAddr = {0};
PSA_TABLE_ENTRY pSA = NULL;
PIPSEC_ACQUIRE_CONTEXT pIpsecAcquireCtx = NULL;
AcquireWriteLock(&g_ipsec.SADBLock, &kIrql);
if (pIpsecGetSPI->SPI) {
if (!(pIpsecGetSPI->InstantiatedFilter.TunnelFilter)) {
pInboundSA = IPSecLookupSABySPI(
pIpsecGetSPI->SPI,
pIpsecGetSPI->InstantiatedFilter.DestAddr
);
}
else {
pInboundSA = IPSecLookupSABySPI(
pIpsecGetSPI->SPI,
pIpsecGetSPI->InstantiatedFilter.TunnelAddr
);
}
if (pInboundSA) {
ntStatus = STATUS_UNSUCCESSFUL;
BAIL_ON_LOCK_NTSTATUS_ERROR(ntStatus);
}
}
ntStatus = IPSecResponderCreateLarvalSA(
pIpsecGetSPI,
uliSrcDstAddr,
&pSA
);
BAIL_ON_LOCK_NTSTATUS_ERROR(ntStatus);
//
// Get the acquire Context and associate it with the larval SA.
//
pIpsecAcquireCtx = IPSecGetAcquireContext();
if (!pIpsecAcquireCtx) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
BAIL_ON_LOCK_NTSTATUS_ERROR(ntStatus);
}
pIpsecAcquireCtx->AcquireId = (ULONG)(ULONG_PTR) pSA;
IPSecGenerateRandom(
(PUCHAR)&pIpsecAcquireCtx->AcquireId,
sizeof(ULONG)
);
pIpsecAcquireCtx->pSA = pSA;
pSA->sa_AcquireId = pIpsecAcquireCtx->AcquireId;
pIpsecGetSPI->Context = pIpsecAcquireCtx;
pSA->sa_AcquireCtx = pIpsecAcquireCtx;
pIpsecGetSPI->SPI = pSA->sa_SPI;
ntStatus = STATUS_SUCCESS;
lock:
ReleaseWriteLock(&g_ipsec.SADBLock, kIrql);
return (ntStatus);
}
NTSTATUS
IPSecResponderCreateLarvalSA(
PIPSEC_GET_SPI pIpsecGetSPI,
ULARGE_INTEGER uliAddr,
PSA_TABLE_ENTRY * ppSA
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PSA_TABLE_ENTRY pSA = NULL;
KIRQL kIrql;
ntStatus = IPSecCreateSA(&pSA);
BAIL_ON_NTSTATUS_ERROR(ntStatus);
pSA->sa_Filter = NULL;
pSA->sa_State = STATE_SA_LARVAL;
IPSEC_BUILD_SRC_DEST_ADDR(
pSA->sa_uliSrcDstAddr,
pIpsecGetSPI->InstantiatedFilter.SrcAddr,
pIpsecGetSPI->InstantiatedFilter.DestAddr
);
IPSEC_BUILD_SRC_DEST_MASK(
pSA->sa_uliSrcDstMask,
pIpsecGetSPI->InstantiatedFilter.SrcMask,
pIpsecGetSPI->InstantiatedFilter.DestMask
);
IPSEC_BUILD_PROTO_PORT_LI(
pSA->sa_uliProtoSrcDstPort,
pIpsecGetSPI->InstantiatedFilter.Protocol,
pIpsecGetSPI->InstantiatedFilter.SrcPort,
pIpsecGetSPI->InstantiatedFilter.DestPort
);
ntStatus = IPSecResponderInsertInboundSA(
pSA,
pIpsecGetSPI,
pIpsecGetSPI->InstantiatedFilter.TunnelFilter
);
BAIL_ON_NTSTATUS_ERROR(ntStatus);
ACQUIRE_LOCK(&g_ipsec.LarvalListLock, &kIrql);
InsertTailList(&g_ipsec.LarvalSAList, &pSA->sa_LarvalLinkage);
IPSEC_INC_STATISTIC(dwNumPendingKeyOps);
RELEASE_LOCK(&g_ipsec.LarvalListLock, kIrql);
ACQUIRE_LOCK(&pSA->sa_Lock, &kIrql);
IPSecStartSATimer(
pSA,
IPSecSAExpired,
pSA->sa_ExpiryTime
);
RELEASE_LOCK(&pSA->sa_Lock, kIrql);
*ppSA = pSA;
return (ntStatus);
error:
if (pSA) {
IPSecFreeSA(pSA);
}
*ppSA = NULL;
return (ntStatus);
}
NTSTATUS
IPSecInitiatorCreateLarvalSA(
PFILTER pFilter,
ULARGE_INTEGER uliAddr,
PSA_TABLE_ENTRY * ppSA,
UCHAR DestType
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PSA_TABLE_ENTRY pSA = NULL;
ULARGE_INTEGER uliSrcDstAddr = {0};
ULARGE_INTEGER uliSrcDstMask = {0};
ULARGE_INTEGER uliProtoSrcDstPort = {0};
KIRQL kIrql;
ntStatus = IPSecCreateSA(&pSA);
BAIL_ON_NTSTATUS_ERROR(ntStatus);
pSA->sa_Filter = pFilter;
pSA->sa_State = STATE_SA_LARVAL;
uliSrcDstAddr = uliAddr;
uliSrcDstMask = pFilter->uliSrcDstMask;
uliProtoSrcDstPort = pFilter->uliProtoSrcDstPort;
IPSEC_BUILD_SRC_DEST_ADDR(
pSA->sa_uliSrcDstAddr,
DEST_ADDR,
SRC_ADDR
);
IPSEC_BUILD_SRC_DEST_MASK(
pSA->sa_uliSrcDstMask,
DEST_MASK,
SRC_MASK
);
IPSEC_BUILD_PROTO_PORT_LI(
pSA->sa_uliProtoSrcDstPort,
PROTO,
DEST_PORT,
SRC_PORT
);
pSA->sa_DestType=DestType;
ntStatus = IPSecInitiatorInsertInboundSA(
pSA,
pFilter->TunnelFilter
);
BAIL_ON_NTSTATUS_ERROR(ntStatus);
ACQUIRE_LOCK(&g_ipsec.LarvalListLock, &kIrql);
InsertTailList(&g_ipsec.LarvalSAList, &pSA->sa_LarvalLinkage);
IPSEC_INC_STATISTIC(dwNumPendingKeyOps);
RELEASE_LOCK(&g_ipsec.LarvalListLock, kIrql);
ACQUIRE_LOCK(&pSA->sa_Lock, &kIrql);
IPSecStartSATimer(
pSA,
IPSecSAExpired,
pSA->sa_ExpiryTime
);
RELEASE_LOCK(&pSA->sa_Lock, kIrql);
*ppSA = pSA;
return (ntStatus);
error:
if (pSA) {
IPSecFreeSA(pSA);
}
*ppSA = NULL;
return (ntStatus);
}
NTSTATUS
IPSecFindSA(
BOOLEAN bTunnelFilter,
ULARGE_INTEGER uliSrcDstAddr,
ULARGE_INTEGER uliProtoSrcDstPort,
PFILTER * ppFilter,
PSA_TABLE_ENTRY * ppSA
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
if (bTunnelFilter) {
ntStatus = IPSecLookupTunnelSA(
uliSrcDstAddr,
uliProtoSrcDstPort,
ppFilter,
ppSA,
FALSE
);
}
else {
#if GPC
if (IS_GPC_ACTIVE()) {
ntStatus = IPSecLookupGpcMaskedSA(
uliSrcDstAddr,
uliProtoSrcDstPort,
ppFilter,
ppSA,
FALSE
);
}
else {
ntStatus = IPSecLookupMaskedSA(
uliSrcDstAddr,
uliProtoSrcDstPort,
ppFilter,
ppSA,
FALSE
);
}
#else
ntStatus = IPSecLookupMaskedSA(
uliSrcDstAddr,
uliProtoSrcDstPort,
ppFilter,
ppSA,
FALSE
);
#endif
}
return (ntStatus);
}
NTSTATUS
IPSecResponderInsertInboundSA(
PSA_TABLE_ENTRY pSA,
PIPSEC_GET_SPI pIpsecGetSPI,
BOOLEAN bTunnelFilter
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILTER pFilter = NULL;
PSA_TABLE_ENTRY pInboundSA = NULL;
PLIST_ENTRY pSAChain = NULL;
KIRQL kIrql;
tSPI tSpi = 0;
PSA_HASH pHash = NULL;
ntStatus = IPSecFindSA(
bTunnelFilter,
pSA->sa_uliSrcDstAddr,
pSA->sa_uliProtoSrcDstPort,
&pFilter,
&pInboundSA
);
if (!NT_SUCCESS(ntStatus)) {
IPSecBufferEvent(
pSA->SA_SRC_ADDR,
EVENT_IPSEC_NEG_FAILURE,
1,
FALSE
);
return (ntStatus);
}
ASSERT(pFilter);
if (pIpsecGetSPI->InstantiatedFilter.Protocol != pFilter->PROTO ||
pIpsecGetSPI->InstantiatedFilter.SrcPort != FI_SRC_PORT(pFilter) ||
pIpsecGetSPI->InstantiatedFilter.DestPort != FI_DEST_PORT(pFilter)) {
ntStatus = STATUS_OBJECT_TYPE_MISMATCH;
return (ntStatus);
}
pSAChain = IPSecResolveSAChain(pFilter, pSA->SA_SRC_ADDR);
InsertHeadList(pSAChain, &pSA->sa_FilterLinkage);
pSA->sa_Flags |= FLAGS_SA_ON_FILTER_LIST;
if (pFilter->Flags & FILTER_FLAGS_PASS_THRU) {
pSA->sa_Flags |= FLAGS_SA_PASSTHRU_FILTER;
}
if (pFilter->TunnelFilter) {
pSA->sa_Flags |= FLAGS_SA_TUNNEL;
pSA->sa_TunnelAddr = pFilter->TunnelAddr;
}
//
// Flush this filter from the cache table so that the SA instead of the
// filter is matched on the next lookup.
//
if (IS_EXEMPT_FILTER(pFilter)) {
IPSecInvalidateFilterCacheEntry(pFilter);
}
AcquireWriteLock(&g_ipsec.SPIListLock, &kIrql);
tSpi = pIpsecGetSPI->SPI;
ntStatus = IPSecAllocateSPI(&tSpi, pSA);
if (!NT_SUCCESS(ntStatus)) {
ReleaseWriteLock(&g_ipsec.SPIListLock, kIrql);
return (ntStatus);
}
pSA->sa_SPI = tSpi;
IPSEC_HASH_SPI(
(pSA->sa_TunnelAddr) ? pSA->sa_TunnelAddr : pSA->SA_DEST_ADDR,
tSpi,
pHash
);
InsertHeadList(&pHash->SAList, &pSA->sa_SPILinkage);
pSA->sa_Flags |= FLAGS_SA_ON_SPI_HASH;
ReleaseWriteLock(&g_ipsec.SPIListLock, kIrql);
return (STATUS_SUCCESS);
}
NTSTATUS
IPSecInitiatorInsertInboundSA(
PSA_TABLE_ENTRY pSA,
BOOLEAN bTunnelFilter
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILTER pFilter = NULL;
PSA_TABLE_ENTRY pInboundSA = NULL;
PLIST_ENTRY pSAChain = NULL;
KIRQL kIrql;
tSPI tSpi = 0;
PSA_HASH pHash = NULL;
ntStatus = IPSecFindSA(
bTunnelFilter,
pSA->sa_uliSrcDstAddr,
pSA->sa_uliProtoSrcDstPort,
&pFilter,
&pInboundSA
);
if (!NT_SUCCESS(ntStatus)) {
IPSecBufferEvent(
pSA->SA_SRC_ADDR,
EVENT_IPSEC_NEG_FAILURE,
1,
FALSE
);
return (ntStatus);
}
if (ntStatus == STATUS_SUCCESS) {
if (pInboundSA->sa_State == STATE_SA_LARVAL) {
ntStatus = STATUS_DUPLICATE_OBJECTID;
return (ntStatus);
}
}
ASSERT(pFilter);
pSAChain = IPSecResolveSAChain(pFilter, pSA->SA_SRC_ADDR);
InsertHeadList(pSAChain, &pSA->sa_FilterLinkage);
pSA->sa_Flags |= FLAGS_SA_ON_FILTER_LIST;
if (pFilter->Flags & FILTER_FLAGS_PASS_THRU) {
pSA->sa_Flags |= FLAGS_SA_PASSTHRU_FILTER;
}
if (pFilter->TunnelFilter) {
pSA->sa_Flags |= FLAGS_SA_TUNNEL;
pSA->sa_TunnelAddr = pFilter->TunnelAddr;
}
//
// Flush this filter from the cache table so that the SA instead of the
// filter is matched on the next lookup.
//
if (IS_EXEMPT_FILTER(pFilter)) {
IPSecInvalidateFilterCacheEntry(pFilter);
}
AcquireWriteLock(&g_ipsec.SPIListLock, &kIrql);
tSpi = 0;
ntStatus = IPSecAllocateSPI(&tSpi, pSA);
if (!NT_SUCCESS(ntStatus)) {
ReleaseWriteLock(&g_ipsec.SPIListLock, kIrql);
return (ntStatus);
}
pSA->sa_SPI = tSpi;
IPSEC_HASH_SPI(
(pSA->sa_TunnelAddr) ? pSA->sa_TunnelAddr : pSA->SA_DEST_ADDR,
tSpi,
pHash
);
InsertHeadList(&pHash->SAList, &pSA->sa_SPILinkage);
pSA->sa_Flags |= FLAGS_SA_ON_SPI_HASH;
ReleaseWriteLock(&g_ipsec.SPIListLock, kIrql);
return (STATUS_SUCCESS);
}