|
|
/////////////////////////////////////////////////////////////
// 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; }
|