windows-nt/Source/XPSP1/NT/net/tcpip/tpipv6/ipsec/ipsec.c
2020-09-26 16:20:57 +08:00

2215 lines
54 KiB
C

// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
//
// Copyright (c) 1985-2000 Microsoft Corporation
//
// This file is part of the Microsoft Research IPv6 Network Protocol Stack.
// You should have received a copy of the Microsoft End-User License Agreement
// for this software along with this release; see the file "license.txt".
// If not, please see http://www.research.microsoft.com/msripv6/license.htm,
// or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
//
// Abstract:
//
// IP Security Policy/Association management tool.
//
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ws2ip6.h>
#include <ntddip6.h>
#include <ip6.h>
#include <stdio.h>
#include <stdlib.h>
//
// Localization library and MessageIds.
//
#include <nls.h>
#include "localmsg.h"
#include "ipsec.h"
#define MAX_KEY_SIZE 1024
typedef struct ipv6_create_sa_and_key {
IPV6_CREATE_SECURITY_ASSOCIATION SA;
unsigned char Key[MAX_KEY_SIZE];
} IPV6_CREATE_SA_AND_KEY;
void CreateSecurityPolicyFile(char *BaseName);
void CreateSecurityAssociationFile(char *BaseName);
void DisplaySecurityPolicyList(unsigned int Interface);
void DisplaySecurityAssociationList(void);
void ReadConfigurationFile(char *BaseName, int Type);
void DeleteSecurityEntry(int Type, unsigned int Index);
int AdminAccess = TRUE;
HANDLE V6Stack;
IPv6Addr UnspecifiedAddr = { 0 };
//
// Entry types.
//
#define POLICY 1
#define ASSOCIATION 0
//
// Amount of "____" space.
//
#define SA_FILE_BORDER 251 // orig 236
#define SP_FILE_BORDER 273 // was 263, orig 258
//
// Transport Protocols
//
#define IP_PROTOCOL_TCP 6
#define IP_PROTOCOL_UDP 17
#define IP_PROTOCOL_ICMPv6 58
PWCHAR
GetString(int ErrorCode, BOOL System)
{
DWORD Count;
static WCHAR ErrorString[2048]; // a 2K static buffer should suffice
Count = FormatMessageW(
(System
? FORMAT_MESSAGE_FROM_SYSTEM
: FORMAT_MESSAGE_FROM_HMODULE) |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
0,
ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
ErrorString,
2048,
NULL);
if (Count == 0) { // failure
return L""; // return a null string
}
return ErrorString; // success
}
#define GetErrorString(ErrorCode) GetString(ErrorCode, TRUE)
void
usage(void)
{
NlsPutMsg(STDOUT, IPSEC_MESSAGE_0);
// printf("\nManipulates IPv6 IPSec security policies and associations.\n\n");
// printf("IPSEC6 [SP [interface] | SA | [L | S] database | "
// "D [SP | SA] index]\n\n");
// printf(" SP [interface] Displays the security policies.\n");
// printf(" SA Displays the security associations.\n");
// printf(" L database Loads the SP and SA entries from the given "
// "database files;\n"
// " database should be the filename without an "
// "extension.\n");
// printf(" S database Saves the current SP and SA entries to the "
// "given database\n"
// " files; database should be the filename "
// "sans extension.\n");
// printf(" D [SP | SA] index Deletes the given policy or association.\n");
// printf("\nSome subcommands require local Administrator privileges.\n");
exit(1);
}
void
ausage(void)
{
NlsPutMsg(STDOUT, IPSEC_MESSAGE_1);
// printf("You do not have local Administrator privileges.\n");
exit(1);
}
void
MakeLowerCase(char *String)
{
while(*String != '\0')
*String++ = (char)tolower(*String);
}
int __cdecl
main(int argc, char **argv)
{
int Error;
WSADATA WsaData;
Error = WSAStartup(MAKEWORD(2, 0), &WsaData);
if (Error) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_2, Error);
// printf("Unable to initialize Windows Sockets, error code %d.\n", Error);
exit(1);
}
//
// First request write access.
// This will fail if the process does not have local Administrator privs.
//
V6Stack = CreateFileW(WIN_IPV6_DEVICE_NAME,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // security attributes
OPEN_EXISTING,
0, // flags & attributes
NULL); // template file
if (V6Stack == INVALID_HANDLE_VALUE) {
//
// We will not have Administrator access to the stack.
//
AdminAccess = FALSE;
V6Stack = CreateFileW(WIN_IPV6_DEVICE_NAME,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // security attributes
OPEN_EXISTING,
0, // flags & attributes
NULL); // template file
if (V6Stack == INVALID_HANDLE_VALUE) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_3);
// printf("Could not access IPv6 protocol stack.\n");
exit(1);
}
}
if (argc < 2) {
usage();
}
MakeLowerCase(argv[1]);
if (!strcmp(argv[1], "sp")) {
unsigned int Interface;
if (argc == 2) {
Interface = 0;
} else {
Interface = atoi(argv[2]);
}
DisplaySecurityPolicyList(Interface);
} else if (!strcmp(argv[1], "sa")) {
DisplaySecurityAssociationList();
} else if (!strcmp(argv[1], "s")) {
if (argc != 3) {
usage();
}
CreateSecurityPolicyFile(argv[2]);
CreateSecurityAssociationFile(argv[2]);
} else if (!strcmp(argv[1], "l")) {
if (!AdminAccess)
ausage();
if (argc != 3) {
usage();
}
ReadConfigurationFile(argv[2], POLICY);
ReadConfigurationFile(argv[2], ASSOCIATION);
} else if (!strcmp(argv[1], "d")) {
unsigned int Index;
int Type;
if (!AdminAccess)
ausage();
if (argc != 4) {
usage();
}
MakeLowerCase(argv[3]);
if (!strcmp(argv[3], "all")) {
Index = 0;
} else {
Index = atol(argv[3]);
if (Index <= 0) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_4);
// printf("Invalid entry number.\n");
exit(1);
}
}
MakeLowerCase(argv[2]);
if (!strcmp(argv[2], "sp")) {
Type = POLICY;
} else if (!strcmp(argv[2], "sa")) {
Type = ASSOCIATION;
} else {
usage();
}
DeleteSecurityEntry(Type, Index);
} else {
usage();
}
return(0);
}
//* GetSecurityPolicyEntry
//
// Retrieves a Security Policy from the in-kernel list, given its index.
// A query for index zero will return the first index on the list.
//
DWORD // Returns: Windows error code.
GetSecurityPolicyEntry(
unsigned int Interface, // IF index or 0 to wildcard.
unsigned long Index, // Index to lookup, or 0 for first.
IPV6_INFO_SECURITY_POLICY_LIST *Info) // Where to return SP info.
{
IPV6_QUERY_SECURITY_POLICY_LIST Query;
unsigned int BytesReturned;
Query.SPInterface = Interface;
Query.Index = Index;
if (!DeviceIoControl(V6Stack, IOCTL_IPV6_QUERY_SECURITY_POLICY_LIST,
&Query, sizeof(Query), Info, sizeof(*Info),
&BytesReturned, NULL)) {
return GetLastError();
}
if (BytesReturned != sizeof(*Info))
return ERROR_GEN_FAILURE;
return ERROR_SUCCESS;
}
//* CreateSecurityPolicyEntry
//
// Creates a Security Policy entry on the in-kernel list.
//
DWORD // Returns Windows error code.
CreateSecurityPolicyEntry(
IPV6_CREATE_SECURITY_POLICY *NewSP) // Policy to add to kernel.
{
unsigned int BytesReturned;
if (!DeviceIoControl(V6Stack, IOCTL_IPV6_CREATE_SECURITY_POLICY,
NewSP, sizeof(*NewSP), NULL, 0,
&BytesReturned, NULL)) {
return GetLastError();
}
//
// When DeviceIoControl is given a null output buffer, the value returned
// in BytesReturned is undefined. Therefore, we don't check for 0 here.
//
return ERROR_SUCCESS;
}
DWORD
DeleteSecurityPolicyEntry(unsigned int Index)
{
IPV6_QUERY_SECURITY_POLICY_LIST Query;
unsigned long BytesReturned;
Query.Index = Index;
if (!DeviceIoControl(V6Stack, IOCTL_IPV6_DELETE_SECURITY_POLICY,
&Query, sizeof(Query), NULL, 0,
&BytesReturned, NULL)) {
return GetLastError();
}
//
// When DeviceIoControl is given a null output buffer, the value returned
// in BytesReturned is undefined. Therefore, we don't check for 0 here.
//
return ERROR_SUCCESS;
}
//* GetSecurityAssociationEntry
//
// Retrieves a Security Association from the in-kernel list, given its index.
// A query for index zero will return the first index on the list.
//
DWORD
GetSecurityAssociationEntry(
unsigned long Index, // Index to query; 0 for first.
IPV6_INFO_SECURITY_ASSOCIATION_LIST *Info) // Where to return SA info.
{
IPV6_QUERY_SECURITY_ASSOCIATION_LIST Query;
unsigned int BytesReturned;
Query.Index = Index;
if (!DeviceIoControl(V6Stack, IOCTL_IPV6_QUERY_SECURITY_ASSOCIATION_LIST,
&Query, sizeof(Query), Info, sizeof(*Info),
&BytesReturned, NULL)) {
return GetLastError();
}
if (BytesReturned != sizeof(*Info))
return ERROR_GEN_FAILURE;
return ERROR_SUCCESS;
}
//* CreateSecurityAssociationEntry
//
// Creates a Security Association entry on the in-kernel list.
//
DWORD // Returns Windows error code.
CreateSecurityAssociationEntry(
IPV6_CREATE_SA_AND_KEY *NewSA) // Association (and key) to add to kernel.
{
unsigned int BytesReturned;
if (!DeviceIoControl(V6Stack, IOCTL_IPV6_CREATE_SECURITY_ASSOCIATION,
&NewSA->SA, sizeof(NewSA->SA) + NewSA->SA.RawKeySize,
NULL, 0, &BytesReturned, NULL)) {
return GetLastError();
}
//
// When DeviceIoControl is given a null output buffer, the value returned
// in BytesReturned is undefined. Therefore, we don't check for 0 here.
//
return ERROR_SUCCESS;
}
DWORD
DeleteSecurityAssociationEntry(unsigned int Index)
{
IPV6_QUERY_SECURITY_ASSOCIATION_LIST Query;
unsigned long BytesReturned;
Query.Index = Index;
if (!DeviceIoControl(V6Stack, IOCTL_IPV6_DELETE_SECURITY_ASSOCIATION,
&Query, sizeof(Query), NULL, 0,
&BytesReturned, NULL)) {
return GetLastError();
}
//
// When DeviceIoControl is given a null output buffer, the value returned
// in BytesReturned is undefined. Therefore, we don't check for 0 here.
//
return ERROR_SUCCESS;
}
//* DeleteSecurityEntry - delete a security policy or association entry.
//
// Note: In the "delete all" case, it'd be much simpler not to query and
// just delete wildcard until the list came up empty, but then we couldn't
// report the index of any entries that failed to delete.
//
void
DeleteSecurityEntry(
int Type, // Type of entry (POLICY or ASSOCIATION).
unsigned int Index) // Index of entry to delete (0 to delete all).
{
int EntriesDeleted = 0;
int All = FALSE;
DWORD Error;
if (Index == 0) {
All = TRUE;
}
do {
if (All) {
//
// Deleting all entries. Find first on (remaining) list.
//
if (Type == POLICY) {
IPV6_INFO_SECURITY_POLICY_LIST Info;
Error = GetSecurityPolicyEntry(0, 0, &Info);
if (Error == ERROR_SUCCESS) {
Index = Info.SPIndex; // First entry.
} else if (Error == ERROR_NO_MATCH) {
Index = 0; // No more entries exist.
break;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_5,
Error, GetErrorString(Error));
// printf("\nError %u accessing Security Policies: %s.\n",
// Error, strerror(Error));
exit(1);
}
} else {
IPV6_INFO_SECURITY_ASSOCIATION_LIST Info;
Error = GetSecurityAssociationEntry(0, &Info);
if (Error == ERROR_SUCCESS) {
Index = Info.SAIndex; // First entry.
} else if (Error == ERROR_NO_MATCH) {
Index = 0; // No more entries exist.
break;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_6,
Error, GetErrorString(Error));
// printf("\nError %u accessing Security Associations: %s.\n",
// Error, strerror(Error));
exit(1);
}
}
}
if (Type == POLICY) {
Error = DeleteSecurityPolicyEntry(Index);
} else {
Error = DeleteSecurityAssociationEntry(Index);
}
if (Error == ERROR_SUCCESS) {
EntriesDeleted++;
} else {
if (Error == ERROR_NO_MATCH) {
if (!All) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_7, Index);
// printf("Error deleting entry %u: entry doesn't exist.\n", Index);
}
// Otherwise silently ignore ...
} else if (Error == ERROR_GEN_FAILURE) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_8, Index);
// printf("Error deleting entry %u.\n", Index);
} else {
if (Type) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_9,
Error, GetErrorString(Error));
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_56,
Error, GetErrorString(Error));
}
// printf("Error %u accessing security %s: %s.\n", Error,
// Type ? "policies" : "associations", strerror(Error));
break;
}
}
} while (All);
if (Type == POLICY) {
if (EntriesDeleted == 1) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_10, EntriesDeleted);
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_57, EntriesDeleted);
}
// printf("Deleted %d polic%s (and any dependent associations).\n",
// EntriesDeleted, EntriesDeleted == 1 ? "y" : "ies");
} else {
if (EntriesDeleted == 1) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_11, EntriesDeleted);
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_58, EntriesDeleted);
}
// printf("Deleted %d association%s.\n", EntriesDeleted,
// EntriesDeleted == 1 ? "" : "s");
}
}
//* ParseAddress - convert address string to binary representation.
//
int
ParseAddress(char *AddrString, IPv6Addr *Address)
{
struct addrinfo Hint;
struct addrinfo *Result;
memset(&Hint, 0, sizeof Hint);
Hint.ai_family = PF_INET6;
if (getaddrinfo(AddrString, NULL, &Hint, &Result))
return FALSE;
*Address = ((struct sockaddr_in6 *)Result->ai_addr)->sin6_addr;
freeaddrinfo(Result);
return TRUE;
}
//* FormatIPv6Address - convert binary address to string representation.
//
// This is only used in printing SAs, thus the unspecified address
// means "take from policy".
//
char *
FormatIPv6Address(IPv6Addr *Address)
{
static char Buffer[46];
if (IN6_ADDR_EQUAL(Address, &UnspecifiedAddr)) {
strcpy(Buffer, "POLICY");
} else {
struct sockaddr_in6 SockAddr;
memset(&SockAddr, 0, sizeof(SockAddr));
SockAddr.sin6_family = AF_INET6;
memcpy(&SockAddr.sin6_addr, Address, sizeof(*Address));
if (getnameinfo((struct sockaddr *)&SockAddr, sizeof(SockAddr), Buffer,
sizeof(Buffer), NULL, 0, NI_NUMERICHOST)) {
strcpy(Buffer, "<invalid>");
}
}
return Buffer;
}
int
ParseSAAdressEntry(char *AddrString, IPv6Addr *Address)
{
if (!strcmp(AddrString, "POLICY")) {
*Address = UnspecifiedAddr;
} else {
if (!ParseAddress(AddrString, Address)) {
return(FALSE);
}
}
return(TRUE);
}
char *
FormatSPAddressEntry(IPv6Addr *AddressStart, IPv6Addr *AddressEnd,
unsigned int AddressField)
{
const char *PointerReturn;
static char Buffer[100];
char TempBuffer[100];
DWORD Buflen = sizeof Buffer;
struct sockaddr_in6 sin6;
switch (AddressField) {
case WILDCARD_VALUE:
strcpy(Buffer, "*");
break;
case SINGLE_VALUE:
sin6.sin6_family = AF_INET6;
sin6.sin6_port = 0;
sin6.sin6_flowinfo = 0;
sin6.sin6_scope_id = 0;
memcpy(&sin6.sin6_addr, AddressStart, sizeof *AddressStart);
if (WSAAddressToString((struct sockaddr *) &sin6,
sizeof sin6,
NULL, // LPWSAPROTOCOL_INFO
Buffer,
&Buflen) == SOCKET_ERROR) {
strcpy(Buffer, "???");
}
break;
case RANGE_VALUE:
sin6.sin6_family = AF_INET6;
sin6.sin6_port = 0;
sin6.sin6_flowinfo = 0;
sin6.sin6_scope_id = 0;
memcpy(&sin6.sin6_addr, AddressStart, sizeof *AddressStart);
if (WSAAddressToString((struct sockaddr *) &sin6,
sizeof sin6,
NULL, // LPWSAPROTOCOL_INFO
Buffer,
&Buflen) == SOCKET_ERROR) {
strcpy(Buffer, "???");
}
memcpy(&sin6.sin6_addr, AddressEnd, sizeof *AddressEnd);
sin6.sin6_family = AF_INET6;
sin6.sin6_port = 0;
sin6.sin6_flowinfo = 0;
sin6.sin6_scope_id = 0;
if (WSAAddressToString((struct sockaddr *) &sin6,
sizeof sin6,
NULL, // LPWSAPROTOCOL_INFO
TempBuffer,
&Buflen) == SOCKET_ERROR) {
strcpy(TempBuffer, "???");
}
strcat(Buffer, "-");
strcat(Buffer, TempBuffer);
break;
default:
strcpy(Buffer, "???");
break;
}
return Buffer;
}
//* Parse an address entry
//
// Valid forms include:
// The wildcard indicator, "*"
// A single address, e.g. "2001::1"
// A range of addresses, e.g. "2001::1-2001::ffff"
//
void
ParseSPAddressEntry(
char *EntryString, // String we're given to parse.
IPv6Addr *AddressStart, // Return start of range, or single address.
IPv6Addr *AddressEnd, // Return end of range, or unspecified.
unsigned int *AddressType) // Return entry type: WILDCARD, SINGLE, RANGE.
{
char *RangeEntry;
RangeEntry = strchr(EntryString, '-');
if (RangeEntry == NULL) {
//
// Should be a wildcard, or single value.
//
if (!strcmp(EntryString, "*")) {
*AddressType = WILDCARD_VALUE;
*AddressStart = UnspecifiedAddr;
} else {
if (!ParseAddress(EntryString, AddressStart)) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_12, EntryString);
// printf("Bad IPv6 Address, %s.\n", EntryString);
exit(1);
}
*AddressType = SINGLE_VALUE;
}
*AddressEnd = UnspecifiedAddr;
} else {
//
// We were given a range.
// Break entry string into two and parse separately.
//
*RangeEntry++ = '\0';
if (!ParseAddress(EntryString, AddressStart)) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_13, EntryString);
// printf("Bad IPv6 Start Address Range, %s.\n", EntryString);
exit(1);
}
if (!ParseAddress(RangeEntry, AddressEnd)) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_14, RangeEntry);
// printf("Bad IPv6 End Address Range, %s.\n", RangeEntry);
exit(1);
}
*AddressType = RANGE_VALUE;
}
}
char *
FormatIPSecProto(unsigned int ProtoNum)
{
char *Result;
switch(ProtoNum) {
case IP_PROTOCOL_AH:
Result = "AH";
break;
case IP_PROTOCOL_ESP:
Result = "ESP";
break;
case NONE:
Result = "NONE";
break;
default:
Result = "???";
break;
}
return Result;
}
unsigned int
ParseIPSecProto(char *Protocol)
{
unsigned int Result;
if (!strcmp(Protocol, "AH")) {
Result = IP_PROTOCOL_AH;
} else if (!strcmp(Protocol, "ESP")) {
Result = IP_PROTOCOL_ESP;
} else if (!strcmp(Protocol, "NONE")) {
Result = NONE;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_15, Protocol);
// printf("Bad IPsec Protocol Value Entry %s.\n", Protocol);
exit(1);
}
return Result;
}
char *
FormatIPSecMode(unsigned int Mode)
{
char *Result;
switch(Mode) {
case TRANSPORT:
Result = "TRANSPORT";
break;
case TUNNEL:
Result = "TUNNEL";
break;
case NONE:
Result = "*";
break;
default:
Result = "???";
break;
}
return Result;
}
unsigned int
ParseIPSecMode(char *Mode)
{
unsigned int Result;
if (!strcmp(Mode, "TRANSPORT")) {
Result = TRANSPORT;
} else if (!strcmp(Mode, "TUNNEL")) {
Result = TUNNEL;
} else if (!strcmp(Mode, "*")) {
Result = NONE;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_16, Mode);
// printf("Bad IPsec Mode Value Entry %s.\n", Mode);
exit(1);
}
return Result;
}
char *
FormatRemoteGW(unsigned int Mode, IPv6Addr *Address)
{
switch (Mode) {
case TRANSPORT:
return "*";
case TUNNEL:
case NONE:
if (IN6_ADDR_EQUAL(Address, &UnspecifiedAddr)) {
return "*";
} else {
return FormatIPv6Address(Address);
}
}
return NULL;
}
int
ParseRemoteGW(
char *AddrString,
IPv6Addr *Address,
unsigned int Mode)
{
switch (Mode) {
case TRANSPORT:
*Address = UnspecifiedAddr;
break;
case TUNNEL:
case NONE:
if (!strcmp(AddrString, "*")) {
*Address = UnspecifiedAddr;
} else
if (!ParseAddress(AddrString, Address)) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_17);
// printf("Bad IPv6 Address for RemoteGWIPAddr.\n");
exit(1);
}
break;
default:
break;
}
return TRUE;
}
char *
FormatSATransportProto(unsigned short Protocol)
{
char *Result;
switch (Protocol) {
case IP_PROTOCOL_TCP:
Result = "TCP";
break;
case IP_PROTOCOL_UDP:
Result = "UDP";
break;
case IP_PROTOCOL_ICMPv6:
Result = "ICMP";
break;
case NONE:
Result = "POLICY";
break;
default:
Result = "???";
break;
}
return Result;
}
unsigned short
ParseSATransportProto(char *Protocol)
{
unsigned short Result;
if (!strcmp(Protocol, "TCP")) {
Result = IP_PROTOCOL_TCP;
} else if (!strcmp(Protocol, "UDP")) {
Result = IP_PROTOCOL_UDP;
} else if (!strcmp(Protocol, "ICMP")) {
Result = IP_PROTOCOL_ICMPv6;
} else if (!strcmp(Protocol, "POLICY")) {
Result = NONE;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_18, Protocol);
// printf("Bad Protocol Value %s.\n", Protocol);
exit(1);
}
return Result;
}
char *
FormatSPTransportProto(unsigned short Protocol)
{
char *Result;
switch (Protocol) {
case IP_PROTOCOL_TCP:
Result = "TCP";
break;
case IP_PROTOCOL_UDP:
Result = "UDP";
break;
case IP_PROTOCOL_ICMPv6:
Result = "ICMP";
break;
case NONE:
Result = "*";
break;
default:
Result = "???";
break;
}
return Result;
}
unsigned short
ParseSPTransportProto(char *Protocol)
{
unsigned short Result;
if (!strcmp(Protocol, "TCP")) {
Result = IP_PROTOCOL_TCP;
} else if (!strcmp(Protocol, "UDP")) {
Result = IP_PROTOCOL_UDP;
} else if (!strcmp(Protocol, "ICMP")) {
Result = IP_PROTOCOL_ICMPv6;
} else if (!strcmp(Protocol, "*")) {
Result = NONE;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_18, Protocol);
// printf("Bad Protocol Value %s.\n", Protocol);
exit(1);
}
return Result;
}
char *
FormatSAPort(unsigned short Port)
{
static char Buffer[11];
if (Port == NONE) {
strcpy(Buffer, "POLICY");
} else {
_itoa(Port, Buffer, 10);
}
return Buffer;
}
unsigned int
ParseSAPort(char *Port)
{
unsigned int Result;
if (!strcmp(Port, "POLICY") || !strcmp(Port, " ")) {
Result = NONE;
} else {
Result = atoi(Port);
}
return Result;
}
char *
FormatSPPort(
unsigned short PortStart,
unsigned short PortEnd,
unsigned int PortField)
{
char TempBuffer[11];
static char Buffer[22];
switch (PortField) {
case WILDCARD_VALUE:
strcpy(Buffer, "*");
break;
case RANGE_VALUE:
_itoa(PortEnd, TempBuffer, 10);
_itoa(PortStart, Buffer, 10);
strcat(Buffer, "-");
strcat(Buffer, TempBuffer);
break;
case SINGLE_VALUE:
_itoa(PortStart, Buffer, 10);
break;
default:
strcpy(Buffer, "???");
break;
}
return Buffer;
}
void
ParseSPPort(
char *EntryString,
unsigned short *PortStart,
unsigned short *PortEnd,
unsigned int *PortField)
{
char *RangeEntry;
RangeEntry = strchr(EntryString, '-');
if (RangeEntry == NULL) {
//
// Should be a wildcard, or a single value.
//
if (!strcmp(EntryString, "*")) {
*PortField = WILDCARD_VALUE;
*PortStart = NONE;
} else {
*PortField = SINGLE_VALUE;
*PortStart = (unsigned short)atoi(EntryString);
}
*PortEnd = NONE;
} else {
//
// We were given a range.
// Break entry string into two and parse separately.
//
*RangeEntry++ = '\0';
*PortStart = (unsigned short)atoi(EntryString);
*PortEnd = (unsigned short)atoi(RangeEntry);
*PortField = RANGE_VALUE;
}
}
unsigned char *
FormatSelector(unsigned int Selector)
{
char *Buffer;
switch (Selector) {
case PACKET_SELECTOR:
Buffer = "+";
break;
case POLICY_SELECTOR:
Buffer = "-";
break;
default:
Buffer = "?";
break;
}
return Buffer;
}
unsigned int
ParseSelector(char *Selector)
{
unsigned int Result;
if (!strcmp(Selector, "+")) {
Result = PACKET_SELECTOR;
} else if (!strcmp(Selector, "-")) {
Result = POLICY_SELECTOR;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_19);
// printf("Bad value for one of the selector types.\n");
exit(1);
}
return Result;
}
char *
FormatIndex(unsigned long Index)
{
static char Buffer[11];
switch (Index) {
case NONE:
strcpy(Buffer, "NONE");
break;
default:
_itoa(Index, Buffer, 10);
break;
}
return Buffer;
}
unsigned long
ParseIndex(char *Index)
{
unsigned long Result;
if (!strcmp(Index, "NONE")) {
Result = NONE;
} else {
Result = atoi(Index);
}
return Result;
}
char *
FormatDirection(unsigned int Direction)
{
char *Buffer;
switch (Direction) {
case INBOUND:
Buffer = "INBOUND";
break;
case OUTBOUND:
Buffer = "OUTBOUND";
break;
case BIDIRECTIONAL:
Buffer = "BIDIRECT";
break;
default:
Buffer = "???";
break;
}
return Buffer;
}
unsigned int
ParseDirection(char *Direction)
{
unsigned int Result;
if (!strcmp(Direction, "INBOUND")) {
Result = INBOUND;
} else if (!strcmp(Direction, "OUTBOUND")) {
Result = OUTBOUND;
} else if (!strcmp(Direction, "BIDIRECT")) {
Result = BIDIRECTIONAL;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_20, Direction);
// printf("Bad Direction Value Entry %s.\n", Direction);
exit(1);
}
return Result;
}
char *
FormatIPSecAction(unsigned int PolicyFlag)
{
char *Result;
switch (PolicyFlag) {
case IPSEC_BYPASS:
Result = "BYPASS";
break;
case IPSEC_DISCARD:
Result = "DISCARD";
break;
case IPSEC_APPLY:
Result = "APPLY";
break;
case IPSEC_APPCHOICE:
Result = "APPCHOICE";
break;
default:
Result = "???";
break;
}
return Result;
}
unsigned int
ParseIPSecAction(char *Action)
{
unsigned int Result;
if (!strcmp(Action, "BYPASS")) {
Result = IPSEC_BYPASS;
} else if (!strcmp(Action, "DISCARD")) {
Result = IPSEC_DISCARD;
} else if (!strcmp(Action, "APPLY")) {
Result = IPSEC_APPLY;
} else if (!strcmp(Action, "APPCHOICE")) {
Result = IPSEC_APPCHOICE;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_21, Action);
// printf("Bad IPSec Action Value Entry %s.\n", Action);
exit(1);
}
return Result;
}
char *
FormatAuthAlg(unsigned int AlgorithmId)
{
char *Result;
switch (AlgorithmId) {
case ALGORITHM_NULL:
Result = "NULL";
break;
case ALGORITHM_HMAC_MD5:
Result = "HMAC-MD5";
break;
case ALGORITHM_HMAC_MD5_96:
Result = "HMAC-MD5-96";
break;
case ALGORITHM_HMAC_SHA1:
Result = "HMAC-SHA1";
break;
case ALGORITHM_HMAC_SHA1_96:
Result = "HMAC-SHA1-96";
break;
default:
Result = "???";
break;
}
return Result;
}
unsigned int
ParseAuthAlg(char *AuthAlg)
{
if (!strcmp(AuthAlg, "NULL")) {
return ALGORITHM_NULL;
}
if (!strcmp(AuthAlg, "HMAC-MD5")) {
return ALGORITHM_HMAC_MD5;
}
if (!strcmp(AuthAlg, "HMAC-MD5-96")) {
return ALGORITHM_HMAC_MD5_96;
}
if (!strcmp(AuthAlg, "HMAC-SHA1")) {
return ALGORITHM_HMAC_SHA1;
}
if (!strcmp(AuthAlg, "HMAC-SHA1-96")) {
return ALGORITHM_HMAC_SHA1_96;
}
NlsPutMsg(STDOUT, IPSEC_MESSAGE_22, AuthAlg);
// printf("Bad Authentication Algorithm Value Entry %s.\n", AuthAlg);
exit(1);
}
unsigned int
ReadKeyFile(
char *FileName,
unsigned char *Key)
{
FILE *KeyFile;
unsigned int KeySize;
if (!strcmp(FileName, "NONE")) {
// This is for NULL algorithm.
strcpy(Key, "NO KEY");
KeySize = strlen(Key);
} else {
if ((KeyFile = fopen(FileName, "r")) == NULL) {
return 0;
}
KeySize = fread(Key, sizeof(unsigned char), MAX_KEY_SIZE, KeyFile);
fclose(KeyFile);
}
return KeySize;
}
//* PrintSecurityPolicyEntry
//
// Print out the security policy entry, "nicely"? formatted,
// to the given file.
//
PrintSecurityPolicyEntry(
FILE *File,
IPV6_INFO_SECURITY_POLICY_LIST *SPEntry)
{
fprintf(File, "%-10lu", SPEntry->SPIndex);
fprintf(File, "%-2s", FormatSelector(SPEntry->RemoteAddrSelector));
fprintf(File, "%-45s", FormatSPAddressEntry(&(SPEntry->RemoteAddr),
&(SPEntry->RemoteAddrData),
SPEntry->RemoteAddrField));
fprintf(File, "%-2s", FormatSelector(SPEntry->LocalAddrSelector));
fprintf(File, "%-45s", FormatSPAddressEntry(&(SPEntry->LocalAddr),
&(SPEntry->LocalAddrData),
SPEntry->LocalAddrField));
fprintf(File, "%-2s", FormatSelector(SPEntry->TransportProtoSelector));
fprintf(File, "%-12s", FormatSPTransportProto(SPEntry->TransportProto));
fprintf(File, "%-2s", FormatSelector(SPEntry->RemotePortSelector));
fprintf(File, "%-12s", FormatSPPort(SPEntry->RemotePort,
SPEntry->RemotePortData,
SPEntry->RemotePortField));
fprintf(File, "%-2s", FormatSelector(SPEntry->LocalPortSelector));
fprintf(File, "%-12s", FormatSPPort(SPEntry->LocalPort,
SPEntry->LocalPortData,
SPEntry->LocalPortField));
fprintf(File, "%-15s", FormatIPSecProto(SPEntry->IPSecProtocol));
fprintf(File, "%-12s", FormatIPSecMode(SPEntry->IPSecMode));
fprintf(File, "%-45s", FormatRemoteGW(SPEntry->IPSecMode,
&(SPEntry->RemoteSecurityGWAddr)));
fprintf(File, "%-15s", FormatIndex(SPEntry->SABundleIndex));
fprintf(File, "%-12s", FormatDirection(SPEntry->Direction));
fprintf(File, "%-12s", FormatIPSecAction(SPEntry->IPSecAction));
fprintf(File, "%-15u", SPEntry->SPInterface);
fprintf(File, ";\n");
}
//* PrintSecurityPolicyHeader
//
// Print out the security policy header fields to the given file.
//
PrintSecurityPolicyHeader(
FILE *File)
{
int Loop;
fprintf(File, "%-10s", "Policy");
fprintf(File, "%-2s", " ");
fprintf(File, "%-45s", "RemoteIPAddr");
fprintf(File, "%-2s", " ");
fprintf(File, "%-45s", "LocalIPAddr");
fprintf(File, "%-2s", " ");
fprintf(File, "%-12s", "Protocol");
fprintf(File, "%-2s", " ");
fprintf(File, "%-12s", "RemotePort");
fprintf(File, "%-2s", " ");
fprintf(File, "%-12s", "LocalPort");
fprintf(File, "%-15s", "IPSecProtocol");
fprintf(File, "%-12s", "IPSecMode");
fprintf(File, "%-45s", "RemoteGWIPAddr");
fprintf(File, "%-15s", "SABundleIndex");
fprintf(File, "%-12s", "Direction");
fprintf(File, "%-12s", "Action");
fprintf(File, "%-15s", "InterfaceIndex");
fprintf(File, "\n");
for (Loop = 0; Loop < SP_FILE_BORDER; Loop++) {
fprintf(File, "_");
}
fprintf(File, "\n");
}
//* PrintSecurityPolicyFooter
//
// Print out the security policy footer to the given file.
//
PrintSecurityPolicyFooter(
FILE *File)
{
int Loop;
for (Loop = 0; Loop < SP_FILE_BORDER; Loop++) {
fprintf(File, "_");
}
fprintf(File, "\n\n");
fprintf(File, "- = Take selector from policy.\n");
fprintf(File, "+ = Take selector from packet.\n");
}
//* PrintSecurityAssociationEntry
//
// Print out the security association entry, "nicely"? formatted,
// to the given file.
//
PrintSecurityAssociationEntry(
FILE *File,
IPV6_INFO_SECURITY_ASSOCIATION_LIST *SAEntry)
{
fprintf(File, "%-10lu", SAEntry->SAIndex);
fprintf(File, "%-15lu", SAEntry->SPI);
fprintf(File, "%-45s", FormatIPv6Address(&(SAEntry->SADestAddr)));
fprintf(File, "%-45s", FormatIPv6Address(&(SAEntry->DestAddr)));
fprintf(File, "%-45s", FormatIPv6Address(&(SAEntry->SrcAddr)));
fprintf(File, "%-12s", FormatSATransportProto(SAEntry->TransportProto));
fprintf(File, "%-12s", FormatSAPort(SAEntry->DestPort));
fprintf(File, "%-12s", FormatSAPort(SAEntry->SrcPort));
fprintf(File, "%-12s", FormatAuthAlg(SAEntry->AlgorithmId));
fprintf(File, "%-15s", " ");
fprintf(File, "%-12s", FormatDirection(SAEntry->Direction));
fprintf(File, "%-15lu", SAEntry->SecPolicyIndex);
fprintf(File, "%-1;");
fprintf(File, "\n");
}
//* PrintSecurityAssociationHeader
//
// Print out the security association header fields to the given file.
//
PrintSecurityAssociationHeader(
FILE *File)
{
int Loop;
fprintf(File, "Security Association List\n\n");
fprintf(File, "%-10s", "SAEntry");
fprintf(File, "%-15s", "SPI");
fprintf(File, "%-45s", "SADestIPAddr");
fprintf(File, "%-45s", "DestIPAddr");
fprintf(File, "%-45s", "SrcIPAddr");
fprintf(File, "%-12s", "Protocol");
fprintf(File, "%-12s", "DestPort");
fprintf(File, "%-12s", "SrcPort");
fprintf(File, "%-12s", "AuthAlg");
fprintf(File, "%-15s", "KeyFile");
fprintf(File, "%-12s", "Direction");
fprintf(File, "%-15s", "SecPolicyIndex");
fprintf(File, "\n");
for (Loop = 0; Loop < SA_FILE_BORDER; Loop++) {
fprintf(File, "_");
}
fprintf(File, "\n");
}
//* PrintSecurityAssociationFooter
//
// Print out the security association footer to the given file.
//
PrintSecurityAssociationFooter(
FILE *File)
{
int Loop;
for (Loop = 0; Loop < SA_FILE_BORDER; Loop++) {
fprintf(File, "_");
}
fprintf(File, "\n");
}
void
CreateSecurityPolicyFile(char *BaseName)
{
IPV6_INFO_SECURITY_POLICY_LIST Info;
char FileName[MAX_PATH + 1];
FILE *File;
unsigned long Index;
DWORD Error;
//
// Copy the filename from the command line to our own buffer so we can
// append an extension to it. We reserve at least 4 characters for the
// extension. The strncpy function will zero fill up to the limit of
// the copy, thus the character at the limit will be NULL unless the
// command line field was too long to fit.
//
strncpy(FileName, BaseName, MAX_PATH - 3);
if (FileName[MAX_PATH - 4] != 0) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_23);
// printf("\nFilename length is too long.\n");
exit(1);
}
strcat(FileName, ".spd");
if ((File = fopen(FileName, "w+")) == NULL) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_24, FileName);
// printf("\nFile %s could not be opened.\n", FileName);
exit(1);
}
//
// Find index of first policy on the in-kernel list.
//
Error = GetSecurityPolicyEntry(0, 0, &Info);
switch (Error) {
case ERROR_SUCCESS:
Index = Info.SPIndex; // First entry.
break;
case ERROR_NO_MATCH:
Index = 0; // No entries exist.
break;
default:
NlsPutMsg(STDOUT, IPSEC_MESSAGE_25, Error, GetErrorString(Error));
// printf("\nError %u reading Security Policies: %s.\n",
// Error, strerror(Error));
Index = 0;
break;
}
fprintf(File, "\nSecurity Policy List\n\n");
PrintSecurityPolicyHeader(File);
//
// Loop through all the policies on the list.
//
while (Index != 0) {
Error = GetSecurityPolicyEntry(0, Index, &Info);
if (Error != ERROR_SUCCESS) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_25, Error, GetErrorString(Error));
// printf("\nError %u reading Security Policies: %s.\n",
// Error, strerror(Error));
break;
}
PrintSecurityPolicyEntry(File, &Info);
Index = Info.NextSPIndex;
}
PrintSecurityPolicyFooter(File);
fclose(File);
NlsPutMsg(STDOUT, IPSEC_MESSAGE_26, FileName);
// printf("Security Policy Data -> %s\n", FileName);
return;
}
void
CreateSecurityAssociationFile(char *BaseName)
{
IPV6_INFO_SECURITY_ASSOCIATION_LIST Info;
char FileName[MAX_PATH + 1];
FILE *File;
unsigned long Index;
DWORD Error;
//
// Copy the filename from the command line to our own buffer so we can
// append an extension to it. We reserve at least 4 characters for the
// extension. The strncpy function will zero fill up to the limit of
// the copy, thus the character at the limit will be NULL unless the
// command line field was too long to fit.
//
strncpy(FileName, BaseName, MAX_PATH - 3);
if (FileName[MAX_PATH - 4] != 0) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_27);
// printf("\nFilename length is too long.\n");
exit(1);
}
strcat(FileName, ".sad");
if ((File = fopen(FileName, "w+")) == NULL) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_28, FileName);
// printf("\nFile %s could not be opened.\n", FileName);
exit(1);
}
//
// Find index of first association on the in-kernel list.
//
Error = GetSecurityAssociationEntry(0, &Info);
switch (Error) {
case ERROR_SUCCESS:
Index = Info.SAIndex; // First entry.
break;
case ERROR_NO_MATCH:
Index = 0; // No entries exist.
break;
default:
NlsPutMsg(STDOUT, IPSEC_MESSAGE_29, Error, GetErrorString(Error));
// printf("\nError %u reading Security Associations: %s.\n",
// Error, strerror(Error));
Index = 0;
break;
}
PrintSecurityAssociationHeader(File);
//
// Loop through all the associations on the list.
//
while (Index != 0) {
Error = GetSecurityAssociationEntry(Index, &Info);
if (Error != ERROR_SUCCESS) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_29, Error, GetErrorString(Error));
// printf("\nError %u reading Security Associations: %s.\n",
// Error, strerror(Error));
break;
}
PrintSecurityAssociationEntry(File, &Info);
Index = Info.NextSAIndex;
}
PrintSecurityAssociationFooter(File);
fclose(File);
NlsPutMsg(STDOUT, IPSEC_MESSAGE_30, FileName);
// printf("Security Association Data -> %s\n", FileName);
return;
}
void
DisplaySecurityPolicyList(unsigned int Interface)
{
IPV6_INFO_SECURITY_POLICY_LIST Info;
unsigned long Index;
DWORD Error;
//
// Find index of first policy on the in-kernel list.
//
Error = GetSecurityPolicyEntry(Interface, 0, &Info);
switch (Error) {
case ERROR_SUCCESS:
Index = Info.SPIndex; // First entry.
break;
case ERROR_NOT_FOUND:
NlsPutMsg(STDOUT, IPSEC_MESSAGE_31, Interface);
// printf("Interface %u does not exist.\n", Interface);
exit(1);
case ERROR_NO_MATCH:
NlsPutMsg(STDOUT, IPSEC_MESSAGE_32);
// printf("No Security Policies exist");
if (Interface != 0) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_33, Interface);
// printf(" for interface %d", Interface);
}
NlsPutMsg(STDOUT, IPSEC_MESSAGE_34);
// printf(".\n");
exit(1);
default:
NlsPutMsg(STDOUT, IPSEC_MESSAGE_25, Error, GetErrorString(Error));
// printf("\nError %u reading Security Policies: %s.\n",
// Error, strerror(Error));
exit(1);
}
if (Interface == 0) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_35);
// printf("\nAll Security Policies\n\n");
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_36, Interface);
// printf("\nSecurity Policy List for Interface %d\n\n", Interface);
}
PrintSecurityPolicyHeader(stdout);
//
// Loop through all the policies on the list.
//
while (Index != 0) {
Error = GetSecurityPolicyEntry(Interface, Index, &Info);
if (Error != ERROR_SUCCESS) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_25, Error, GetErrorString(Error));
// printf("\nError %u reading Security Policies: %s.\n",
// Error, strerror(Error));
exit(1);
}
PrintSecurityPolicyEntry(stdout, &Info);
Index = Info.NextSPIndex;
}
PrintSecurityPolicyFooter(stdout);
return;
}
void
DisplaySecurityAssociationList(void)
{
IPV6_INFO_SECURITY_ASSOCIATION_LIST Info;
unsigned long Index;
DWORD Error;
//
// Find index of first association on the in-kernel list.
//
Error = GetSecurityAssociationEntry(0, &Info);
switch (Error) {
case ERROR_SUCCESS:
Index = Info.SAIndex; // First entry.
break;
case ERROR_NO_MATCH:
// There are no SA entries yet.
NlsPutMsg(STDOUT, IPSEC_MESSAGE_37);
// printf("No Security Associations exist.\n");
exit(1);
default:
NlsPutMsg(STDOUT, IPSEC_MESSAGE_29, Error, GetErrorString(Error));
// printf("\nError %u reading Security Associations: %s.\n",
// Error, strerror(Error));
exit(1);
}
NlsPutMsg(STDOUT, IPSEC_MESSAGE_38);
// printf("\n");
PrintSecurityAssociationHeader(stdout);
//
// Loop through all the associations on the list.
//
while (Index != 0) {
Error = GetSecurityAssociationEntry(Index, &Info);
if (Error != ERROR_SUCCESS) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_29, Error, GetErrorString(Error));
// printf("\nError %u reading Security Associations: %s.\n",
// Error, strerror(Error));
exit(1);
}
PrintSecurityAssociationEntry(stdout, &Info);
Index = Info.NextSAIndex;
}
PrintSecurityAssociationFooter(stdout);
return;
}
int
ParseSPLine(
char *Line, // Line to parse.
IPV6_CREATE_SECURITY_POLICY *SP) // Where to put the data.
{
char *Token;
Token = strtok(Line, " ");
if (Token == NULL) {
return FALSE;
}
// Policy Number.
SP->SPIndex = atol(Token);
// RemoteIPAddr Selector.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->RemoteAddrSelector = ParseSelector(Token);
// RemoteIPAddr.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
ParseSPAddressEntry(Token, &SP->RemoteAddr, &SP->RemoteAddrData,
&SP->RemoteAddrField);
// LocalIPAddr Selector.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->LocalAddrSelector = ParseSelector(Token);
// LocalIPAddr.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
ParseSPAddressEntry(Token, &SP->LocalAddr, &SP->LocalAddrData,
&SP->LocalAddrField);
// Protocol Selector.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->TransportProtoSelector = ParseSelector(Token);
// Protocol.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->TransportProto = ParseSPTransportProto(Token);
// RemotePort Selector.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->RemotePortSelector = ParseSelector(Token);
// RemotePort.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
ParseSPPort(Token, &SP->RemotePort, &SP->RemotePortData,
&SP->RemotePortField);
// LocalPort Selector.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->LocalPortSelector = ParseSelector(Token);
// Local Port.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
ParseSPPort(Token, &SP->LocalPort, &SP->LocalPortData,
&SP->LocalPortField);
// IPSecProtocol.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->IPSecProtocol = ParseIPSecProto(Token);
// IPSecMode.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->IPSecMode = ParseIPSecMode(Token);
// RemoteGWIPAddr.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
ParseRemoteGW(Token, &SP->RemoteSecurityGWAddr, SP->IPSecMode);
// SABundleIndex.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->SABundleIndex = ParseIndex(Token);
// Direction.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->Direction = ParseDirection(Token);
// Action.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->IPSecAction = ParseIPSecAction(Token);
// Interface SP.
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SP->SPInterface = atol(Token);
// End of current policy.
// REVIEW: Insist that nothing follows final valid field on the line?
// if ((Token = strtok(NULL, " ")) != NULL) return FALSE;
return TRUE;
}
int
ParseSALine(
char *Line, // Line to parse.
IPV6_CREATE_SA_AND_KEY *SAAndKey) // Where to put the data.
{
char *Token;
IPV6_CREATE_SECURITY_ASSOCIATION *SA = &(SAAndKey->SA);
Token = strtok(Line, " ");
if (Token == NULL) {
return FALSE;
}
// Security Association Entry Number.
SA->SAIndex = atol(Token);
// SPI
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SA->SPI = atol(Token);
// SADestAddr
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
ParseSAAdressEntry(Token, &SA->SADestAddr);
// DestIPAddr
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
ParseSAAdressEntry(Token, &SA->DestAddr);
// SrcIPAddr
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
ParseSAAdressEntry(Token, &SA->SrcAddr);
// Protocol
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SA->TransportProto = ParseSATransportProto(Token);
// DestPort
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SA->DestPort = (unsigned short)ParseSAPort(Token);
// SrcPort
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SA->SrcPort = (unsigned short)ParseSAPort(Token);
// AuthAlg
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SA->AlgorithmId = ParseAuthAlg(Token);
// KeyFile
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SA->RawKeySize = ReadKeyFile(Token, SAAndKey->Key);
if (SA->RawKeySize == 0) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_39, Token);
// printf("Error reading key file %s\n", Token);
return FALSE;
}
// Direction
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SA->Direction = ParseDirection(Token);
// SecPolicyIndex
if ((Token = strtok(NULL, " ")) == NULL) return FALSE;
SA->SecPolicyIndex = atol(Token);
// End of current association.
// REVIEW: Insist that nothing follows final valid field on the line?
// if ((Token = strtok(NULL, " ")) != NULL) return FALSE;
return TRUE;
}
void
ReadConfigurationFile(char *BaseName, int Type)
{
char Buffer[SP_FILE_BORDER + 2]; // Note: SP_FILE_BORDER > SA_FILE_BORDER
char FileName[MAX_PATH + 1];
unsigned int MaxLineLengthPlusOne, LineLength, Line;
FILE *File;
int ParseIt = 0;
IPV6_CREATE_SECURITY_POLICY SPEntry;
IPV6_CREATE_SA_AND_KEY SAEntry;
int Policies = 0;
int Associations = 0;
DWORD Error;
//
// Copy the filename from the command line to our own buffer so we can
// append an extension to it. We reserve at least 4 characters for the
// extension. The strncpy function will zero fill up to the limit of
// the copy, thus the character at the limit will be NULL unless the
// command line field was too long to fit.
//
strncpy(FileName, BaseName, MAX_PATH - 3);
if (FileName[MAX_PATH - 4] != 0) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_40);
// printf("\nFilename length is too long.\n");
exit(1);
}
//
// Add appropriate file extension.
// Maximum line length is the size of the field entries
// plus one for the newline character. Since we need to
// fgets with a value one greater than the max that can
// be read in, we add that onto the maximum line length
// to get MaxLineLengthPlusOne. Saves us an add later.
//
if (Type == POLICY) {
strcat(FileName, ".spd");
MaxLineLengthPlusOne = SP_FILE_BORDER + 2;
} else {
if (Type == ASSOCIATION) {
strcat(FileName, ".sad");
MaxLineLengthPlusOne = SA_FILE_BORDER + 2;
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_41);
// printf("\nReadConfigurationFile routine called incorrectly.\n");
exit(1);
}
}
if ((File = fopen(FileName, "r")) == NULL) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_42, FileName);
// printf("\nFile %s could not be opened.\n", FileName);
exit(1);
}
for (Line = 1; !feof(File); Line++) {
if (fgets(Buffer, MaxLineLengthPlusOne, File) == NULL)
break;
LineLength = strlen(Buffer);
// printf("Line = %u, Length = %u: %s.\n", Line, LineLength, Buffer);
if (Buffer[LineLength - 1] != '\n') {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_43, Line);
// printf("Error on line %u, line too long.\n", Line);
break;
} else {
Buffer[LineLength - 1] = '\0';
}
if (ParseIt) {
if (Buffer[0] == '_')
break;
if (Type == POLICY) {
if (!ParseSPLine(Buffer, &SPEntry)) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_44, Line);
// printf("Error parsing SP entry fields on line %u.\n", Line);
break;
} else {
Error = CreateSecurityPolicyEntry(&SPEntry);
if (Error == ERROR_ALREADY_EXISTS) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_45,
Line, SPEntry.SPIndex);
// printf("Error on line %u: a policy with index %u "
// "already exists.\n", Line, SPEntry.SPIndex);
continue;
}
if (Error == ERROR_NOT_FOUND) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_46,
Line, SPEntry.SPIndex);
// printf("Error on line %u: policy %u specifies a "
// "non-existent interface.\n",
// Line, SPEntry.SPIndex);
continue;
}
if (Error != ERROR_SUCCESS) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_47,
Error,
Line,
SPEntry.SPIndex,
GetErrorString(Error));
// printf("Error %u on line %u, policy %u: %s.\n",
// Error, Line, SPEntry.SPIndex, strerror(Error));
break;
}
Policies++;
}
} else {
if (!ParseSALine(Buffer, &SAEntry)) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_48, Line);
// printf("Error parsing SA entry fields on line %u.\n", Line);
break;
} else {
Error = CreateSecurityAssociationEntry(&SAEntry);
if (Error == ERROR_ALREADY_EXISTS) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_49,
Line, SAEntry.SA.SAIndex);
// printf("Error on line %u: an association with index "
// "%u already exists.\n", Line,
// SAEntry.SA.SAIndex);
continue;
}
if (Error != ERROR_SUCCESS) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_50,
Error, SAEntry.SA.SAIndex, GetErrorString(Error));
// printf("Error %u adding association %u: %s.\n",
// Error, SAEntry.SA.SAIndex, strerror(Error));
break;
}
Associations++;
}
}
}
if (Buffer[0] == '_')
ParseIt = TRUE;
}
if (Type == POLICY) {
if (Policies == 1) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_51, Policies);
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_59, Policies);
}
// printf("Added %d polic%s.\n", Policies, Policies == 1 ? "y" : "ies");
} else {
if (Associations == 1) {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_52, Associations);
} else {
NlsPutMsg(STDOUT, IPSEC_MESSAGE_60, Associations);
}
// printf("Added %d association%s.\n",
// Associations, Associations == 1 ? "" : "s");
}
}