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.
 
 
 
 
 
 

1307 lines
38 KiB

/////////////////////////////////////////////////////////////
// Copyright(c) 2000-2001, Microsoft Corporation
//
// text2spd.cpp
//
// Created on 2/15/00 by DKalin
// Revisions:
// Split into text2spd.cpp and spdutil.cpp 3/27/01 DKalin
//
// Moved the routines to this module from text2pol.cpp 2/15/00 DKalin
//
// Implementation for the text to policy conversion routines that deal directly with SPD structures
//
// Separated from generic routines in text2pol.cpp
//
/////////////////////////////////////////////////////////////
#include "ipseccmd.h"
// if szSrc and/or szDst are passed in,
// caller must provide adequate space
DWORD TextToFilter(IN char *szText, IN OUT T2P_FILTER &Filter, char *szSrc, char *szDst)
{
DWORD dwReturn = T2P_OK; // return code of this function
char *pToken = NULL, *pTmp = NULL;
char szTmp[POTF_MAX_STRLEN];
char *pPortTok = NULL,
*pProtTok = NULL;
BOOL bMirror = false;
if (szText != NULL) // do not assume that caller is smart
{
// We copy szText to szTmp so we can muck with it
// in the process, we
// determine passthru or drop filter
// but first we set this filter to negotiate security and to be not mirrored
// we also set protocol field
if (Filter.QMFilterType != QM_TUNNEL_FILTER)
{
// transport filter
// the very first thing we do is check for default response rule specified
// then we set both Inbound and Outbound filter flags to POTF_DEFAULT_RESPONSE_FLAG
// and substitute "DEFAULT" string with "0+0" (Me-to-Me)
if (_stricmp(POTF_FILTER_DEFAULT, szText) == 0)
{
Filter.TransportFilter.InboundFilterFlag = (FILTER_FLAG) POTF_DEFAULT_RESPONSE_FLAG;
Filter.TransportFilter.OutboundFilterFlag = (FILTER_FLAG) POTF_DEFAULT_RESPONSE_FLAG;
szText[0] = '0';
szText[1] = '+';
szText[2] = '0';
szText[3] = '\0';
}
else
{
Filter.TransportFilter.InboundFilterFlag = NEGOTIATE_SECURITY;
Filter.TransportFilter.OutboundFilterFlag = NEGOTIATE_SECURITY;
}
Filter.TransportFilter.bCreateMirror = FALSE;
Filter.TransportFilter.Protocol.ProtocolType = PROTOCOL_UNIQUE;
Filter.TransportFilter.Protocol.dwProtocol = 0;
}
else
{
// tunnel filter
Filter.TunnelFilter.InboundFilterFlag = NEGOTIATE_SECURITY;
Filter.TunnelFilter.OutboundFilterFlag = NEGOTIATE_SECURITY;
Filter.TunnelFilter.bCreateMirror = FALSE;
Filter.TunnelFilter.Protocol.ProtocolType = PROTOCOL_UNIQUE;
Filter.TunnelFilter.Protocol.dwProtocol = 0;
UuidCreateNil(&(Filter.TunnelFilter.SrcTunnelAddr.gInterfaceID));
UuidCreateNil(&(Filter.TunnelFilter.DesTunnelAddr.gInterfaceID));
}
pToken = strchr(szText, POTF_PASSTHRU_OPEN_TOKEN);
if (pToken != NULL)
{
if (strrchr(szText, POTF_PASSTHRU_CLOSE_TOKEN) == NULL)
{
dwReturn = T2P_PASSTHRU_NOT_CLOSED;
}
else
{
strcpy(szTmp, szText + 1);
szTmp[strlen(szTmp) - 1] = '\0';
if (Filter.QMFilterType != QM_TUNNEL_FILTER)
{
// transport filter
Filter.TransportFilter.InboundFilterFlag = PASS_THRU;
Filter.TransportFilter.OutboundFilterFlag = PASS_THRU;
}
else
{
// tunnel filter
Filter.TunnelFilter.InboundFilterFlag = PASS_THRU;
Filter.TunnelFilter.OutboundFilterFlag = PASS_THRU;
}
}
}
else if ( (pToken = strchr(szText, POTF_DROP_OPEN_TOKEN)) != NULL )
{
if (strrchr(szText, POTF_DROP_CLOSE_TOKEN) == NULL)
{
dwReturn = T2P_DROP_NOT_CLOSED;
}
else
{
strcpy(szTmp, szText + 1);
szTmp[strlen(szTmp) - 1] = '\0';
if (Filter.QMFilterType != QM_TUNNEL_FILTER)
{
// transport filter
Filter.TransportFilter.dwFlags |= FILTER_NATURE_BLOCKING;
Filter.TransportFilter.InboundFilterFlag = BLOCKING;
Filter.TransportFilter.OutboundFilterFlag = BLOCKING;
}
else
{
// tunnel filter
Filter.TunnelFilter.dwFlags |= FILTER_NATURE_BLOCKING;
Filter.TunnelFilter.InboundFilterFlag = BLOCKING;
Filter.TunnelFilter.OutboundFilterFlag = BLOCKING;
}
}
}
else
strcpy(szTmp, szText);
// parse into source and dest strings
for (pToken = szText; *pToken != POTF_FILTER_TOKEN &&
*pToken != POTF_FILTER_MIRTOKEN &&
*pToken != '\0'; ++pToken)
;
if (*pToken == '\0')
{
dwReturn = T2P_NOSRCDEST_TOKEN;
}
else if ( *(pToken + 1) == '\0' )
{
dwReturn = T2P_NO_DESTADDR;
}
else if (T2P_SUCCESS(dwReturn))
{
if (*pToken == POTF_FILTER_MIRTOKEN)
{
bMirror = TRUE;
// set Mirrored = true
if (Filter.QMFilterType != QM_TUNNEL_FILTER)
{
// transport filter
Filter.TransportFilter.bCreateMirror = TRUE;
}
else
{
// tunnel filter
Filter.TunnelFilter.bCreateMirror = TRUE;
}
}
if (!bMirror)
pToken = strchr(szTmp, POTF_FILTER_TOKEN);
else
pToken = strchr(szTmp, POTF_FILTER_MIRTOKEN);
*pToken = '\0';
// do the src address
dwReturn = TextToFiltAddr(szTmp, Filter, szSrc);
if (T2P_SUCCESS(dwReturn))
{
// do the dest address
pPortTok = strchr(pToken + 1, POTF_PT_TOKEN);
if (pPortTok == NULL) // no port/prot specified
dwReturn = TextToFiltAddr(pToken + 1, Filter, szDst, true);
else if ( (pProtTok = strchr(pPortTok + 1, POTF_PT_TOKEN)) == NULL )
{
// there is a port but not a protocol specified
// this is illegal (bug 285266)
dwReturn = T2P_INVALID_ADDR;
}
else
{
// there is both port and protocol specified
*pProtTok = '\0';
dwReturn = TextToFiltAddr(pToken + 1, Filter, szDst, true);
if (T2P_SUCCESS(dwReturn))
{
if (Filter.QMFilterType != QM_TUNNEL_FILTER)
{
// transport filter
Filter.TransportFilter.Protocol.ProtocolType = PROTOCOL_UNIQUE;
dwReturn = TextToProtocol(pProtTok + 1, Filter.TransportFilter.Protocol.dwProtocol);
}
else
{
// tunnel filter
Filter.TunnelFilter.Protocol.ProtocolType = PROTOCOL_UNIQUE;
dwReturn = TextToProtocol(pProtTok + 1, Filter.TunnelFilter.Protocol.dwProtocol);
}
}
}
}
// we're done, do any fixing up of Filter
if (T2P_SUCCESS(dwReturn))
{
if (Filter.QMFilterType != QM_TUNNEL_FILTER)
{
// transport filter
// set the GUID
RPC_STATUS RpcStat = UuidCreate(&Filter.TransportFilter.gFilterID);
if (RpcStat != RPC_S_OK && RpcStat != RPC_S_UUID_LOCAL_ONLY)
{
dwReturn = RpcStat;
}
// set the name to be equal to the "text2pol " + GUID
if (T2P_SUCCESS(dwReturn))
{
WCHAR StringTxt[POTF_MAX_STRLEN];
int iReturn;
wcscpy(StringTxt, L"text2pol ");
iReturn = StringFromGUID2(Filter.TransportFilter.gFilterID, StringTxt+wcslen(StringTxt), POTF_MAX_STRLEN-wcslen(StringTxt));
assert(iReturn != 0);
Filter.TransportFilter.pszFilterName = new WCHAR[wcslen(StringTxt)+1];
assert(Filter.TransportFilter.pszFilterName != NULL);
wcscpy(Filter.TransportFilter.pszFilterName, StringTxt);
}
}
else
{
// tunnel filter
// set the GUID
RPC_STATUS RpcStat = UuidCreate(&Filter.TunnelFilter.gFilterID);
if (RpcStat != RPC_S_OK && RpcStat != RPC_S_UUID_LOCAL_ONLY)
{
dwReturn = RpcStat;
}
// set the name to be equal to the "text2pol " + GUID
if (T2P_SUCCESS(dwReturn))
{
WCHAR StringTxt[POTF_MAX_STRLEN];
int iReturn;
wcscpy(StringTxt, L"text2pol ");
iReturn = StringFromGUID2(Filter.TunnelFilter.gFilterID, StringTxt+wcslen(StringTxt), POTF_MAX_STRLEN-wcslen(StringTxt));
assert(iReturn != 0);
Filter.TunnelFilter.pszFilterName = new WCHAR[wcslen(StringTxt)+1];
assert(Filter.TunnelFilter.pszFilterName != NULL);
wcscpy(Filter.TunnelFilter.pszFilterName, StringTxt);
}
}
}
}
}
else // szText is NULL
dwReturn = T2P_NULL_STRING;
return dwReturn;
}
DWORD TextToFiltAddr(IN char *szAddr, IN OUT T2P_FILTER & Filter,
OUT char *szName,
IN bool bDest) // bDest is false
{
DWORD dwReturn = T2P_OK;
IPAddr Address = INADDR_NONE;
IPMask Mask = INADDR_NONE;
WORD Port = 0;
char *pMask = NULL,
*pPort = NULL,
*pPeek = NULL;
bool bInterface = false;
GUID gInterfaceId;
struct hostent *pHostEnt;
if (szAddr != NULL)
{
// copy szAddr so we can muck with it
char szTmp[POTF_MAX_STRLEN];
strcpy(szTmp, szAddr);
// let's see what we have here
if ( (pPort = strrchr(szTmp, POTF_PT_TOKEN)) != NULL )
{
*pPort = '\0';
++pPort;
}
if ( (pMask = strrchr(szTmp, POTF_MASK_TOKEN)) != NULL )
{
*pMask = '\0';
++pMask;
}
// first, the easy cases
// To specify ME, use 0 for the address and -1 for the mask
// To specify ANY use 0 for the address and 0 for the mask.
if (szTmp[0] == POTF_ANYADDR_TOKEN)
{
Address = SUBNET_ADDRESS_ANY;
Mask = SUBNET_MASK_ANY;
}
else if (szTmp[0] == POTF_ME_TOKEN)
{
Address = IP_ADDRESS_ME;
Mask = IP_ADDRESS_MASK_NONE;
}
else if (szTmp[0] == POTF_GUID_TOKEN)
{ // interface-specific filter
char *pGUIDEnd = NULL;
if ( (pGUIDEnd = strrchr(szTmp, POTF_GUID_END_TOKEN)) != NULL )
{
*pGUIDEnd = '\0';
}
if (pGUIDEnd && UuidFromStringA((unsigned char *)(szTmp+1), &gInterfaceId) == RPC_S_OK)
{
bInterface = true;
}
else
{
dwReturn = T2P_INVALID_ADDR;
}
}
else if (isdnsname(szTmp)) // DNS name
{
pHostEnt = gethostbyname(szTmp);
if (pHostEnt != NULL)
{
Address = *(IPAddr *)pHostEnt->h_addr;
// should check for more here, but not now
// specific host, Mask is 255.255.255.255
Mask = IP_ADDRESS_MASK_NONE;
}
else
{
dwReturn = T2P_DNSLOOKUP_FAILED;
}
if ( szName )
strcpy(szName, szTmp);
}
else // good old dotted notation
{
// process the * shortcut for subnetting
if (strchr(szTmp, POTF_STAR_TOKEN) != NULL)
{
Mask = 0x000000FF;
for (pPeek = szTmp; *pPeek != '\0'; ++pPeek)
{
if ((*pPeek == '.') && (*(pPeek + 1) != POTF_STAR_TOKEN))
Mask |= (Mask << 8);
else if ((*pPeek == '.') && (*(pPeek + 1) != '\0'))
*(pPeek + 1) = '0';
}
}
Address = inet_addr(szTmp);
if (Address == INADDR_NONE)
{
dwReturn = T2P_INVALID_ADDR;
}
else
{
if (pMask != NULL)
{
Mask = inet_addr(pMask);
}
else if (pPeek == NULL)
Mask = IP_ADDRESS_MASK_NONE;
}
}
// now for the port and fill the Filter out
if (T2P_SUCCESS(dwReturn))
{
if (pPort != NULL)
{
Port = (SHORT)atoi(pPort);
}
if (Filter.QMFilterType != QM_TUNNEL_FILTER)
{
// transport filter
if (bDest) // we converted the dest addr
{
if (!bInterface)
{
Filter.TransportFilter.DesAddr.AddrType = (Mask == IP_ADDRESS_MASK_NONE) ? IP_ADDR_UNIQUE : IP_ADDR_SUBNET;
Filter.TransportFilter.DesAddr.uIpAddr = Address;
Filter.TransportFilter.DesAddr.uSubNetMask = Mask;
Filter.TransportFilter.DesPort.PortType = PORT_UNIQUE;
Filter.TransportFilter.DesPort.wPort = Port;
UuidCreateNil(&(Filter.TransportFilter.DesAddr.gInterfaceID));
}
else
{
Filter.TransportFilter.DesAddr.AddrType = IP_ADDR_INTERFACE;
Filter.TransportFilter.DesAddr.uIpAddr = IP_ADDRESS_ME;
Filter.TransportFilter.DesAddr.uSubNetMask = IP_ADDRESS_MASK_NONE;
Filter.TransportFilter.DesPort.PortType = PORT_UNIQUE;
Filter.TransportFilter.DesPort.wPort = Port;
Filter.TransportFilter.DesAddr.gInterfaceID = gInterfaceId;
}
}
else
{
if (!bInterface)
{
Filter.TransportFilter.SrcAddr.AddrType = (Mask == IP_ADDRESS_MASK_NONE) ? IP_ADDR_UNIQUE : IP_ADDR_SUBNET;
Filter.TransportFilter.SrcAddr.uIpAddr = Address;
Filter.TransportFilter.SrcAddr.uSubNetMask = Mask;
Filter.TransportFilter.SrcPort.PortType = PORT_UNIQUE;
Filter.TransportFilter.SrcPort.wPort = Port;
UuidCreateNil(&(Filter.TransportFilter.SrcAddr.gInterfaceID));
}
else
{
Filter.TransportFilter.SrcAddr.AddrType = IP_ADDR_INTERFACE;
Filter.TransportFilter.SrcAddr.uIpAddr = IP_ADDRESS_ME;
Filter.TransportFilter.SrcAddr.uSubNetMask = IP_ADDRESS_MASK_NONE;
Filter.TransportFilter.SrcPort.PortType = PORT_UNIQUE;
Filter.TransportFilter.SrcPort.wPort = Port;
Filter.TransportFilter.SrcAddr.gInterfaceID = gInterfaceId;
}
}
}
else
{
// tunnel filter
if (bDest) // we converted the dest addr
{
if (!bInterface)
{
Filter.TunnelFilter.DesAddr.AddrType = (Mask == IP_ADDRESS_MASK_NONE) ? IP_ADDR_UNIQUE : IP_ADDR_SUBNET;
Filter.TunnelFilter.DesAddr.uIpAddr = Address;
Filter.TunnelFilter.DesAddr.uSubNetMask = Mask;
Filter.TunnelFilter.DesPort.PortType = PORT_UNIQUE;
Filter.TunnelFilter.DesPort.wPort = Port;
UuidCreateNil(&(Filter.TunnelFilter.DesAddr.gInterfaceID));
}
else
{
Filter.TunnelFilter.DesAddr.AddrType = IP_ADDR_INTERFACE;
Filter.TunnelFilter.DesAddr.uIpAddr = IP_ADDRESS_ME;
Filter.TunnelFilter.DesAddr.uSubNetMask = IP_ADDRESS_MASK_NONE;
Filter.TunnelFilter.DesPort.PortType = PORT_UNIQUE;
Filter.TunnelFilter.DesPort.wPort = Port;
Filter.TunnelFilter.DesAddr.gInterfaceID = gInterfaceId;
}
}
else
{
if (!bInterface)
{
Filter.TunnelFilter.SrcAddr.AddrType = (Mask == IP_ADDRESS_MASK_NONE) ? IP_ADDR_UNIQUE : IP_ADDR_SUBNET;
Filter.TunnelFilter.SrcAddr.uIpAddr = Address;
Filter.TunnelFilter.SrcAddr.uSubNetMask = Mask;
Filter.TunnelFilter.SrcPort.PortType = PORT_UNIQUE;
Filter.TunnelFilter.SrcPort.wPort = Port;
UuidCreateNil(&(Filter.TunnelFilter.SrcAddr.gInterfaceID));
}
else
{
Filter.TunnelFilter.SrcAddr.AddrType = IP_ADDR_INTERFACE;
Filter.TunnelFilter.SrcAddr.uIpAddr = IP_ADDRESS_ME;
Filter.TunnelFilter.SrcAddr.uSubNetMask = IP_ADDRESS_MASK_NONE;
Filter.TunnelFilter.SrcPort.PortType = PORT_UNIQUE;
Filter.TunnelFilter.SrcPort.wPort = Port;
Filter.TunnelFilter.SrcAddr.gInterfaceID = gInterfaceId;
}
}
}
}
}
else
dwReturn = T2P_NULL_STRING;
return dwReturn;
}
DWORD TextToProtocol(IN char *szProt, OUT DWORD & dwProtocol)
{
DWORD dwReturn = T2P_OK;
if (szProt != NULL)
{
// is it special string
if (isalpha(szProt[0]))
{
if (_stricmp(szProt, POTF_TCP_STR) == 0)
dwProtocol = (POTF_TCP_PROTNUM);
else if (_stricmp(szProt, POTF_UDP_STR) == 0)
dwProtocol = (POTF_UDP_PROTNUM);
else if (_stricmp(szProt, POTF_ICMP_STR) == 0)
dwProtocol = (POTF_ICMP_PROTNUM);
else if (_stricmp(szProt, POTF_RAW_STR) == 0)
dwProtocol = (POTF_RAW_PROTNUM);
else
{
dwReturn = T2P_INVALID_PROTOCOL;
}
}
else
{
dwProtocol = ((DWORD)atol(szProt));
}
}
return dwReturn;
}
DWORD TextToOffer(IN char *szText, IN OUT IPSEC_QM_OFFER & Offer)
{
DWORD dwReturn = T2P_OK;
char szTmp[POTF_MAX_STRLEN];
char *pAnd = NULL,
*pOptions = NULL,
*pString = NULL;
if (szText != NULL)
{
// we will for sure overwrite the Count and Algos
// since they are required for valid conversion
Offer.dwNumAlgos = 0;
Offer.dwPFSGroup = 0;
// copy szText so we can muck it up
strcpy(szTmp, szText);
// process Rekey and PFS first
pOptions = strrchr(szTmp, POTF_NEGPOL_CLOSE);
if ((pOptions != NULL) && *(pOptions + 1) != '\0')
{
++pOptions; // we have options
pString = strchr(pOptions, POTF_NEGPOL_PFS);
if (pString != NULL)
{
char *pStr;
Offer.bPFSRequired = TRUE;
Offer.dwPFSGroup = PFS_GROUP_MM;
pStr = strchr(pString, '1');
if (pStr)
{
Offer.dwPFSGroup = PFS_GROUP_1;
}
pStr = strchr(pString, '2');
if (pStr)
{
Offer.dwPFSGroup = PFS_GROUP_2;
}
*pString = '\0';
}
if (pString != pOptions) // user could have specified just PFS
{
// process key lifetime
// two params specified?
pString = strchr(pOptions, POTF_REKEY_TOKEN);
if (pString != NULL)
{
*pString = '\0';
++pString;
switch (pString[strlen(pString) - 1])
{
case 'k':
case 'K':
pString[strlen(pString) - 1] = '\0';
Offer.Lifetime.uKeyExpirationKBytes = atol(pString);
if ( Offer.Lifetime.uKeyExpirationKBytes < POTF_MIN_P2LIFE_BYTES )
{
dwReturn = T2P_P2REKEY_TOO_LOW;
}
break;
case 's':
case 'S':
pString[strlen(pString) - 1] = '\0';
Offer.Lifetime.uKeyExpirationTime = atol(pString);
if ( Offer.Lifetime.uKeyExpirationTime < POTF_MIN_P2LIFE_TIME )
{
dwReturn = T2P_P2REKEY_TOO_LOW;
}
break;
default:
dwReturn = T2P_INVALID_P2REKEY_UNIT;
break;
}
}
switch (pOptions[strlen(pOptions) - 1])
{
case 'k':
case 'K':
pOptions[strlen(pOptions) - 1] = '\0';
Offer.Lifetime.uKeyExpirationKBytes = atol(pOptions);
if ( Offer.Lifetime.uKeyExpirationKBytes < POTF_MIN_P2LIFE_BYTES )
{
dwReturn = T2P_P2REKEY_TOO_LOW;
}
break;
case 's':
case 'S':
pOptions[strlen(pOptions) - 1] = '\0';
Offer.Lifetime.uKeyExpirationTime = atol(pOptions);
if ( Offer.Lifetime.uKeyExpirationTime < POTF_MIN_P2LIFE_TIME )
{
dwReturn = T2P_P2REKEY_TOO_LOW;
}
break;
default:
dwReturn = T2P_INVALID_P2REKEY_UNIT;
break;
}
}
// important: we have to do this here so the alginfo
// gets processed ok:
*pOptions = '\0';
}
if ( T2P_SUCCESS(dwReturn) )
{
// now process the ipsec protocol spec AH, ESP
pAnd = strchr(szTmp, POTF_NEGPOL_AND);
if ( pAnd != NULL )
{
// we have an AND proposal
*pAnd = '\0';
++pAnd;
dwReturn = TextToAlgoInfo(szTmp, Offer.Algos[Offer.dwNumAlgos]);
++Offer.dwNumAlgos;
if ( T2P_SUCCESS(dwReturn) )
{
dwReturn = TextToAlgoInfo(pAnd, Offer.Algos[Offer.dwNumAlgos]);
++Offer.dwNumAlgos;
}
}
else
{
dwReturn = TextToAlgoInfo(szTmp, Offer.Algos[Offer.dwNumAlgos]);
++Offer.dwNumAlgos;
}
}
}
else
dwReturn = T2P_NULL_STRING;
return dwReturn;
}
DWORD TextToAlgoInfo(IN char *szText, OUT IPSEC_QM_ALGO & algoInfo)
{
DWORD dwReturn = T2P_OK;
char szTmp[POTF_MAX_STRLEN];
char *pOpen = NULL,
*pClose = NULL,
*pString = NULL;
// these are used for processing AND to default to NONE
bool bEncryption = false, bAuthentication= false;
if (szText == NULL)
return T2P_NULL_STRING;
// muck with the string so we can copy it ;)
strcpy(szTmp, szText);
algoInfo.uAlgoKeyLen = algoInfo.uAlgoRounds = 0;
pOpen = strchr(szTmp, POTF_NEGPOL_OPEN);
pClose = strrchr(szTmp, POTF_NEGPOL_CLOSE);
if ((pOpen != NULL) && (pClose != NULL) && (*(pClose + 1) == '\0')) // defense
{
*pOpen = '\0';
*pClose = '\0';
++pOpen;
if (_stricmp(szTmp, POTF_NEGPOL_AH) == 0)
{
if (_stricmp(pOpen, POTF_NEGPOL_MD5) == 0)
algoInfo.uAlgoIdentifier = IPSEC_DOI_AH_MD5;
else if (_stricmp(pOpen, POTF_NEGPOL_SHA) == 0 || _stricmp(pOpen, POTF_NEGPOL_SHA1) == 0)
algoInfo.uAlgoIdentifier = IPSEC_DOI_AH_SHA1;
else
{
dwReturn = T2P_INVALID_HASH_ALG;
}
algoInfo.Operation = AUTHENTICATION;
}
else if (_stricmp(szTmp, POTF_NEGPOL_ESP) == 0)
{
algoInfo.Operation = ENCRYPTION;
pString = strchr(pOpen, POTF_ESPTRANS_TOKEN);
if (pString != NULL)
{
*pString = '\0';
++pString;
// we allow the hash and encryption to be specified in either
// the first or second field-- hence the long conditionals
if (_stricmp(pOpen, POTF_NEGPOL_DES) == 0)
{
bEncryption = true;
algoInfo.uAlgoIdentifier = IPSEC_DOI_ESP_DES;
}
else if (_stricmp(pOpen, POTF_NEGPOL_3DES) == 0)
{
bEncryption = true;
algoInfo.uAlgoIdentifier = IPSEC_DOI_ESP_3_DES;
}
else if (_stricmp(pOpen, POTF_NEGPOL_MD5) == 0)
{
bAuthentication = true;
algoInfo.uSecAlgoIdentifier = HMAC_AH_MD5;
}
else if (_stricmp(pOpen, POTF_NEGPOL_SHA) == 0 || _stricmp(pOpen, POTF_NEGPOL_SHA1) == 0)
{
bAuthentication = true;
algoInfo.uSecAlgoIdentifier = HMAC_AH_SHA1;
}
else if (_stricmp(pOpen, POTF_NEGPOL_NONE) != 0) // parse error
{
dwReturn = T2P_GENERAL_PARSE_ERROR;
}
// now the second one
if (_stricmp(pString, POTF_NEGPOL_DES) == 0 && !bEncryption)
{
bEncryption = true;
algoInfo.uAlgoIdentifier = IPSEC_DOI_ESP_DES;
}
else if (_stricmp(pString, POTF_NEGPOL_3DES) == 0 && !bEncryption)
{
bEncryption = true;
algoInfo.uAlgoIdentifier = IPSEC_DOI_ESP_3_DES;
}
else if (_stricmp(pString, POTF_NEGPOL_MD5) == 0 && !bAuthentication)
{
bAuthentication = true;
algoInfo.uSecAlgoIdentifier = HMAC_AH_MD5;
}
else if ((_stricmp(pString, POTF_NEGPOL_SHA) == 0 || _stricmp(pString, POTF_NEGPOL_SHA1) == 0) && !bAuthentication)
{
bAuthentication = true;
algoInfo.uSecAlgoIdentifier = HMAC_AH_SHA1;
}
else if (_stricmp(pString, POTF_NEGPOL_NONE) != 0) // parse error
{
dwReturn = T2P_DUP_ALGS;
}
// now, fill in the NONE policies or detect NONE, NONE
if (!bAuthentication && !bEncryption)
{
dwReturn = T2P_NONE_NONE;
}
else if (!bAuthentication)
{
algoInfo.uSecAlgoIdentifier = HMAC_AH_NONE;
}
else if (!bEncryption)
{
algoInfo.uAlgoIdentifier = IPSEC_DOI_ESP_NONE;
}
}
else // error
{
dwReturn = T2P_INCOMPLETE_ESPALGS;
}
}
else
{
dwReturn = T2P_INVALID_IPSECPROT;
}
}
else // error
{
dwReturn = T2P_GENERAL_PARSE_ERROR;
}
return dwReturn;
}
DWORD TextToOakleyAuth(IN char *szText, OUT IPSEC_MM_AUTH_INFO & AuthInfo)
{
DWORD dwReturn = T2P_OK;
char *pString = NULL,
*pTmp = NULL;
char *szTmp = NULL;
char *Info = NULL;
if (szText != NULL)
{
// copy szText so we can muck with it
szTmp = new char[strlen(szText)+1];
assert(szTmp != 0);
strcpy(szTmp, szText);
// parse string
if ( (pString = strchr(szTmp, POTF_OAKAUTH_TOKEN)) != NULL )
*pString = '\0';
// not UNICODE compliant
if (tolower(szTmp[0]) == tolower(POTF_OAKAUTH_PRESHARE[0]))
{
if ((pString != NULL) && (strlen(pString + 1) > 0) )
{
++pString; // now pointing at string
AuthInfo.AuthMethod = IKE_PRESHARED_KEY;
if (*pString == '"') // fix up if the user included quotes
{
++pString;
pTmp = strrchr(pString, '"');
if (pTmp != NULL)
{
*pTmp = '\0';
}
}
// convert to wide and fill in
Info = new char[strlen(pString) + 1];
assert(Info != NULL);
strcpy(Info, pString);
}
else // no key provided
{
dwReturn = T2P_NO_PRESHARED_KEY;
}
}
else if (tolower(szTmp[0]) == tolower(POTF_OAKAUTH_KERBEROS[0]))
{
AuthInfo.AuthMethod = IKE_SSPI;
}
else if (tolower(szTmp[0]) == tolower(POTF_OAKAUTH_CERT[0]))
{
AuthInfo.AuthMethod = IKE_RSA_SIGNATURE;
if ((pString != NULL) && (strlen(pString + 1) > 0) )
{
// CA is indicated
++pString; // now pointing at string
Info = new char[strlen(pString) + 1];
assert(Info != NULL);
if (*pString == '"') // fix up if the user included quotes
{
++pString;
pTmp = strrchr(pString, '"');
if (pTmp != NULL)
{
*pTmp = '\0';
}
}
strcpy(Info, pString);
}
// else the CA will be negotiated
}
else // invalid option
{
dwReturn = T2P_INVALID_AUTH_METHOD;
}
// now convert the ascii to wide char
// authinfo needs to be wide
if (Info != NULL && T2P_SUCCESS(dwReturn))
{
AuthInfo.pAuthInfo = NULL;
AuthInfo.dwAuthInfoSize = 0;
AuthInfo.dwAuthInfoSize = MultiByteToWideChar(CP_THREAD_ACP, 0, Info, -1,
(WCHAR *) AuthInfo.pAuthInfo, 0);
if (AuthInfo.dwAuthInfoSize == 0) // failure
{
dwReturn = T2P_MB2WC_FAILED;
}
else
{
AuthInfo.pAuthInfo = (LPBYTE) new WCHAR[AuthInfo.dwAuthInfoSize];
assert(AuthInfo.pAuthInfo != NULL);
AuthInfo.dwAuthInfoSize = MultiByteToWideChar(CP_THREAD_ACP, 0, Info, -1,
(WCHAR *) AuthInfo.pAuthInfo, AuthInfo.dwAuthInfoSize);
AuthInfo.dwAuthInfoSize--;
AuthInfo.dwAuthInfoSize *= sizeof(WCHAR);
}
if (AuthInfo.dwAuthInfoSize == 0) // failure
{
delete [] AuthInfo.pAuthInfo;
dwReturn = T2P_MB2WC_FAILED;
}
// now do additional conversion if this is cert
if (T2P_SUCCESS(dwReturn) && AuthInfo.AuthMethod == IKE_RSA_SIGNATURE)
{
LPBYTE asnCert;
dwReturn = CM_EncodeName((LPWSTR) AuthInfo.pAuthInfo, &asnCert, &AuthInfo.dwAuthInfoSize);
delete [] AuthInfo.pAuthInfo;
if (dwReturn != ERROR_SUCCESS)
{
dwReturn = T2P_INVALID_AUTH_METHOD;
}
else
{
AuthInfo.pAuthInfo = asnCert;
dwReturn = T2P_OK;
}
}
}
}
else
dwReturn = T2P_NULL_STRING;
if (Info) delete Info;
if (szTmp) delete szTmp;
return dwReturn;
}
DWORD TextToSecMethod(IN char *szText, IN OUT IPSEC_MM_OFFER & SecMethod)
{
DWORD dwReturn = T2P_OK;
char szTmp[POTF_MAX_STRLEN];
char *pString1 = NULL,
*pString2 = NULL;
bool bEncryption = false,
bAuthentication = false;
if (szText == NULL)
return T2P_NULL_STRING;
// copy szText so we can muck it up
strcpy(szTmp, szText);
pString1 = strchr(szTmp, POTF_P1_TOKEN);
pString2 = strrchr(szTmp, POTF_P1_TOKEN);
if ((pString1 != NULL) && (pString2 != NULL) && (pString1 != pString2))
{
// string parsed ok so far
*pString1 = '\0';
*pString2 = '\0';
++pString1;
++pString2;
// we allow the hash and encryption to be specified in either
// the first or second field-- hence the long conditionals
if (_stricmp(szTmp, POTF_P1_DES) == 0)
{
bEncryption = true;
SecMethod.EncryptionAlgorithm.uAlgoIdentifier = IPSEC_DOI_ESP_DES;
SecMethod.EncryptionAlgorithm.uAlgoKeyLen = SecMethod.EncryptionAlgorithm.uAlgoRounds = 0;
}
else if (_stricmp(szTmp, POTF_P1_3DES) == 0)
{
bEncryption = true;
SecMethod.EncryptionAlgorithm.uAlgoIdentifier = IPSEC_DOI_ESP_3_DES;
SecMethod.EncryptionAlgorithm.uAlgoKeyLen = SecMethod.EncryptionAlgorithm.uAlgoRounds = 0;
}
else if (_stricmp(szTmp, POTF_P1_MD5) == 0)
{
bAuthentication = true;
SecMethod.HashingAlgorithm.uAlgoIdentifier = IPSEC_DOI_AH_MD5;
SecMethod.HashingAlgorithm.uAlgoKeyLen = SecMethod.HashingAlgorithm.uAlgoRounds = 0;
}
else if (_stricmp(szTmp, POTF_P1_SHA) == 0)
{
bAuthentication = true;
SecMethod.HashingAlgorithm.uAlgoIdentifier = IPSEC_DOI_AH_SHA1;
SecMethod.HashingAlgorithm.uAlgoKeyLen = SecMethod.HashingAlgorithm.uAlgoRounds = 0;
}
else // parse error
{
dwReturn = T2P_GENERAL_PARSE_ERROR;
}
if (_stricmp(pString1, POTF_P1_DES) == 0 && !bEncryption)
{
bEncryption = true;
SecMethod.EncryptionAlgorithm.uAlgoIdentifier = IPSEC_DOI_ESP_DES;
SecMethod.EncryptionAlgorithm.uAlgoKeyLen = SecMethod.EncryptionAlgorithm.uAlgoRounds = 0;
}
else if (_stricmp(pString1, POTF_P1_3DES) == 0 && !bEncryption)
{
bEncryption = true;
SecMethod.EncryptionAlgorithm.uAlgoIdentifier = IPSEC_DOI_ESP_3_DES;
SecMethod.EncryptionAlgorithm.uAlgoKeyLen = SecMethod.EncryptionAlgorithm.uAlgoRounds = 0;
}
else if (_stricmp(pString1, POTF_P1_MD5) == 0 && !bAuthentication)
{
bAuthentication = true;
SecMethod.HashingAlgorithm.uAlgoIdentifier = IPSEC_DOI_AH_MD5;
SecMethod.HashingAlgorithm.uAlgoKeyLen = SecMethod.HashingAlgorithm.uAlgoRounds = 0;
}
else if (_stricmp(pString1, POTF_P1_SHA) == 0 && !bAuthentication)
{
bAuthentication = true;
SecMethod.HashingAlgorithm.uAlgoIdentifier = IPSEC_DOI_AH_SHA1;
SecMethod.HashingAlgorithm.uAlgoKeyLen = SecMethod.HashingAlgorithm.uAlgoRounds = 0;
}
else // parse error
{
dwReturn = T2P_DUP_ALGS;
}
// now for the group
if (isdigit(pString2[0]))
{
switch (pString2[0])
{
case '1':
SecMethod.dwDHGroup = POTF_OAKLEY_GROUP1;
break;
case '2':
SecMethod.dwDHGroup = POTF_OAKLEY_GROUP2;
break;
default:
dwReturn = T2P_INVALID_P1GROUP;
break;
}
}
else
{
dwReturn = T2P_P1GROUP_MISSING;
}
}
else // parse error
{
dwReturn = T2P_GENERAL_PARSE_ERROR;
}
return dwReturn;
}
DWORD TextToP1Rekey(IN char *szText, IN OUT KEY_LIFETIME & LifeTime, OUT DWORD & QMLim)
{
DWORD dwReturn = T2P_OK;
char szTmp[POTF_MAX_STRLEN];
char *pString = NULL;
if (!szText)
return T2P_NULL_STRING;
// copy szText so we can muck it up
strcpy(szTmp, szText);
// two params specified?
pString = strchr(szTmp, POTF_QM_TOKEN);
if (pString != NULL)
{
*pString = '\0';
++pString;
switch (pString[strlen(pString) - 1])
{
case 'q':
case 'Q':
pString[strlen(pString) - 1] = '\0';
QMLim = atol(pString);
break;
case 's':
case 'S':
pString[strlen(pString) - 1] = '\0';
LifeTime.uKeyExpirationTime = atol(pString);
break;
default:
dwReturn = T2P_INVALID_P1REKEY_UNIT;
break;
}
}
switch (szTmp[strlen(szTmp) - 1])
{
case 'q':
case 'Q':
szTmp[strlen(szTmp) - 1] = '\0';
QMLim = atol(szTmp);
break;
case 's':
case 'S':
szTmp[strlen(szTmp) - 1] = '\0';
LifeTime.uKeyExpirationTime = atol(szTmp);
break;
default:
dwReturn = T2P_INVALID_P1REKEY_UNIT;
break;
}
return dwReturn;
}
// caveat, won't go deep into DNS
DWORD TextToIPAddr(IN char *szText, IN OUT IPAddr & Address)
{
DWORD dwReturn = T2P_OK;
struct hostent *pHostEnt;
if (szText != NULL)
{
if (!strcmp(szText, POTF_ME_TUNNEL))
{
Address = 0;
}
else if (isdnsname(szText)) // DNS name
{
pHostEnt = gethostbyname(szText);
if (pHostEnt != NULL)
{
Address = *(IPAddr *)pHostEnt->h_addr;
// should check for more here, but not now
}
else
{
dwReturn = T2P_DNSLOOKUP_FAILED;
}
}
else // good old dotted notation
{
Address = inet_addr(szText);
if (Address == INADDR_NONE)
{
dwReturn = T2P_INVALID_ADDR;
}
}
}
else
{
dwReturn = T2P_NULL_STRING;
}
return dwReturn;
}
// if szSrc and/or szDst are passed in,
// caller must provide adequate space
DWORD TextToMMFilter(IN char *szText, IN OUT MM_FILTER &Filter, char *szSrc, char *szDst)
{
DWORD dwReturn = T2P_OK; // return code of this function
char *pToken = NULL, *pTmp = NULL;
char szTmp[POTF_MAX_STRLEN];
char *pPortTok = NULL,
*pProtTok = NULL;
BOOL bMirror = false;
T2P_FILTER t2pFilter; // for TextToFilterAddr calls
if (szText != NULL) // do not assume that caller is smart
{
// We copy szText to szTmp so we can muck with it
// in the process, we
// determine passthru or drop filter
// but first we set this filter to negotiate security and to be not mirrored
// we also set protocol field
Filter.bCreateMirror = FALSE;
// set up T2P_FILTER
t2pFilter.QMFilterType = QM_TRANSPORT_FILTER;
memset(&t2pFilter.TransportFilter, 0, sizeof(TRANSPORT_FILTER));
pToken = strchr(szText, POTF_PASSTHRU_OPEN_TOKEN);
if (pToken != NULL)
{
dwReturn = T2P_GENERAL_PARSE_ERROR;
}
else if ( (pToken = strchr(szText, POTF_DROP_OPEN_TOKEN)) != NULL )
{
dwReturn = T2P_GENERAL_PARSE_ERROR;
}
else
strcpy(szTmp, szText);
// parse into source and dest strings
for (pToken = szText; *pToken != POTF_FILTER_TOKEN &&
*pToken != POTF_FILTER_MIRTOKEN &&
*pToken != '\0'; ++pToken)
;
if (*pToken == '\0')
{
dwReturn = T2P_NOSRCDEST_TOKEN;
}
else if ( *(pToken + 1) == '\0' )
{
dwReturn = T2P_NO_DESTADDR;
}
else if (T2P_SUCCESS(dwReturn))
{
if (*pToken == POTF_FILTER_MIRTOKEN)
{
bMirror = TRUE;
// set Mirrored = true
Filter.bCreateMirror = TRUE;
}
if (!bMirror)
pToken = strchr(szTmp, POTF_FILTER_TOKEN);
else
pToken = strchr(szTmp, POTF_FILTER_MIRTOKEN);
*pToken = '\0';
// check for port presence
pPortTok = strchr(szTmp, POTF_PT_TOKEN);
if (pPortTok != NULL)
{
dwReturn = T2P_GENERAL_PARSE_ERROR;
}
else
{
// do the src address
dwReturn = TextToFiltAddr(szTmp, t2pFilter, szSrc);
// copy src address
Filter.SrcAddr = t2pFilter.TransportFilter.SrcAddr;
}
if (T2P_SUCCESS(dwReturn))
{
// do the dest address
pPortTok = strchr(pToken + 1, POTF_PT_TOKEN);
if (pPortTok == NULL) // no port/prot specified
{
dwReturn = TextToFiltAddr(pToken + 1, t2pFilter, szDst, true);
// copy dest address
Filter.DesAddr = t2pFilter.TransportFilter.DesAddr;
}
else
{
// error
dwReturn = T2P_GENERAL_PARSE_ERROR;
}
}
// we're done, do any fixing up of Filter
if (T2P_SUCCESS(dwReturn))
{
// set the GUID
RPC_STATUS RpcStat = UuidCreate(&Filter.gFilterID);
if (RpcStat != RPC_S_OK && RpcStat != RPC_S_UUID_LOCAL_ONLY)
{
dwReturn = RpcStat;
}
// set the name to be equal to the "text2pol " + GUID
if (T2P_SUCCESS(dwReturn))
{
WCHAR StringTxt[POTF_MAX_STRLEN];
int iReturn;
wcscpy(StringTxt, L"text2pol ");
iReturn = StringFromGUID2(Filter.gFilterID, StringTxt+wcslen(StringTxt), POTF_MAX_STRLEN-wcslen(StringTxt));
assert(iReturn != 0);
Filter.pszFilterName = new WCHAR[wcslen(StringTxt)+1];
assert(Filter.pszFilterName != NULL);
wcscpy(Filter.pszFilterName, StringTxt);
}
}
}
}
else // szText is NULL
dwReturn = T2P_NULL_STRING;
return dwReturn;
}