1183 lines
31 KiB
C
1183 lines
31 KiB
C
/*++
|
||
|
||
Copyright (c) 1998, Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
sainfo.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code for managing shared access settings.
|
||
|
||
Shared Access Settings are stored in a file and consist of a list
|
||
of sections which correspond either to 'applications' or 'servers',
|
||
and content indices which list all applications and servers in the file.
|
||
E.g.
|
||
[Contents.Application]
|
||
<key>=1 ; Enabled
|
||
[Contents.Server]
|
||
<key>=1 ; Enabled
|
||
|
||
An 'application' entry specifies parameters for a dynamic ticket
|
||
which will allow the application to work through the NAT,
|
||
by dynamically allowing an inbound secondary session.
|
||
E.g.
|
||
[Application.<key>]
|
||
Title=DirectPlay
|
||
Protocol=TCP
|
||
Port=47624
|
||
TcpResponseList=2300-2400
|
||
UdpResponseList=2300-2400
|
||
BuiltIn=1 ; optional flag, defaults to 0
|
||
|
||
A 'server' entry specifies parameters for a static port mapping
|
||
which will direct all sessions for a particular protocol and port
|
||
to a particular internal machine.
|
||
E.g.
|
||
[Server.<key>]
|
||
Title=WWW
|
||
Protocol=TCP
|
||
Port=80
|
||
InternalName=MACHINENAME
|
||
InternalPort=8080
|
||
ReservedAddress=192.168.0.200
|
||
BuiltIn=0 ; optional flag, defaults to 0
|
||
|
||
Author:
|
||
|
||
Abolade Gbadegesin (aboladeg) 17-Oct-1998
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
#include <pbk.h>
|
||
#include <tchar.h>
|
||
#include <limits.h>
|
||
|
||
#define LSTRLEN(s) ((sizeof(s) / sizeof(TCHAR)) - 1)
|
||
#define HTONS(s) ((UCHAR)((s) >> 8) | ((UCHAR)(s) << 8))
|
||
#define HTONL(l) ((HTONS(l) << 16) | HTONS((l) >> 16))
|
||
#define NTOHS(s) HTONS(s)
|
||
#define NTOHL(l) HTONL(l)
|
||
|
||
#if 0
|
||
|
||
const TCHAR c_szApplication[] = TEXT("Application");
|
||
const TCHAR c_szBuiltIn[] = TEXT("BuiltIn");
|
||
const TCHAR c_szContents[] = TEXT("Contents");
|
||
const TCHAR c_szInternalName[] = TEXT("InternalName");
|
||
const TCHAR c_szInternalPort[] = TEXT("InternalPort");
|
||
const TCHAR c_szKeyFormat[] = TEXT("%08X");
|
||
#endif
|
||
const TCHAR c_szMaxResponseEntry[] = TEXT("65535-65535,");
|
||
#if 0
|
||
const TCHAR c_szPort[] = TEXT("Port");
|
||
const TCHAR c_szProtocol[] = TEXT("Protocol");
|
||
const TCHAR c_szReservedAddress[] = TEXT("ReservedAddress");
|
||
#endif
|
||
const TCHAR c_szResponseFormat1[] = TEXT("%d");
|
||
const TCHAR c_szResponseFormat2[] = TEXT("%d-%d");
|
||
#if 0
|
||
const TCHAR c_szSectionFormat[] = TEXT("%s.%s");
|
||
const TCHAR c_szServer[] = TEXT("Server");
|
||
const TCHAR c_szSharedAccessIni[] = TEXT("SharedAccess.ini");
|
||
const TCHAR c_szTagBuiltIn[] = TEXT("BuiltIn=");
|
||
const TCHAR c_szTagInternalName[] = TEXT("InternalName=");
|
||
const TCHAR c_szTagInternalPort[] = TEXT("InternalPort=");
|
||
const TCHAR c_szTagPort[] = TEXT("Port=");
|
||
const TCHAR c_szTagProtocol[] = TEXT("Protocol=");
|
||
const TCHAR c_szTagReservedAddress[] = TEXT("ReservedAddress=");
|
||
const TCHAR c_szTagTcpResponseList[] = TEXT("TcpResponseList=");
|
||
const TCHAR c_szTagTitle[] = TEXT("Title=");
|
||
const TCHAR c_szTagUdpResponseList[] = TEXT("UdpResponseList=");
|
||
const TCHAR c_szTCP[] = TEXT("TCP");
|
||
const TCHAR c_szTcpResponseList[] = TEXT("TcpResponseList");
|
||
const TCHAR c_szTitle[] = TEXT("Title");
|
||
const TCHAR c_szUDP[] = TEXT("UDP");
|
||
const TCHAR c_szUdpResponseList[] = TEXT("UdpResponseList");
|
||
|
||
//
|
||
// FORWARD DECLARATIONS
|
||
//
|
||
|
||
SAAPPLICATION*
|
||
LoadApplication(
|
||
ULONG KeyValue,
|
||
BOOL Enabled,
|
||
const TCHAR* Path
|
||
);
|
||
|
||
TCHAR*
|
||
LoadEntryList(
|
||
const TCHAR* Path,
|
||
const TCHAR* Section
|
||
);
|
||
|
||
TCHAR*
|
||
LoadPath(
|
||
VOID
|
||
);
|
||
|
||
SASERVER*
|
||
LoadServer(
|
||
ULONG KeyValue,
|
||
BOOL Enabled,
|
||
const TCHAR* Path
|
||
);
|
||
|
||
LONG
|
||
Lstrcmpni(
|
||
const TCHAR* String1,
|
||
const TCHAR* String2,
|
||
LONG Length
|
||
);
|
||
|
||
TCHAR*
|
||
QueryEntryList(
|
||
const TCHAR* EntryList,
|
||
const TCHAR* Tag
|
||
);
|
||
|
||
BOOL
|
||
SaveApplication(
|
||
SAAPPLICATION* Application,
|
||
const TCHAR* Path
|
||
);
|
||
|
||
BOOL
|
||
SaveServer(
|
||
SAINFO* Info,
|
||
SASERVER* Server,
|
||
const TCHAR* Path
|
||
);
|
||
|
||
BOOL
|
||
WritePrivateProfileStringUTF8(
|
||
const TCHAR* Section,
|
||
const TCHAR* Key,
|
||
const TCHAR* Value,
|
||
const TCHAR* Path
|
||
);
|
||
|
||
|
||
VOID APIENTRY
|
||
RasFreeSharedAccessSettings(
|
||
IN SAINFO* Info
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Frees memory allocated for the contents of 'Info'.
|
||
|
||
Arguments:
|
||
|
||
Info - the settings to be freed
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
SAAPPLICATION* Application;
|
||
PLIST_ENTRY Link;
|
||
SASERVER* Server;
|
||
TRACE("RasFreeSharedAccessSettings");
|
||
|
||
while (!IsListEmpty(&Info->ApplicationList)) {
|
||
Link = RemoveHeadList(&Info->ApplicationList);
|
||
Application = CONTAINING_RECORD(Link, SAAPPLICATION, Link);
|
||
FreeSharedAccessApplication(Application);
|
||
}
|
||
|
||
while (!IsListEmpty(&Info->ServerList)) {
|
||
Link = RemoveHeadList(&Info->ServerList);
|
||
Server = CONTAINING_RECORD(Link, SASERVER, Link);
|
||
FreeSharedAccessServer(Server);
|
||
}
|
||
|
||
Free(Info);
|
||
} // RasFreeSharedAccessSettings
|
||
|
||
|
||
SAINFO* APIENTRY
|
||
RasLoadSharedAccessSettings(
|
||
BOOL EnabledOnly
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads in the local shared access settings, returning an allocated
|
||
'SAINFO' containing the settings retrieved.
|
||
|
||
Arguments:
|
||
|
||
EnabledOnly - if TRUE, only the application-entries which are enabled
|
||
are retrieved.
|
||
|
||
Return Value:
|
||
|
||
SAINFO* - the settings retrieved
|
||
|
||
--*/
|
||
|
||
{
|
||
SAAPPLICATION* Application;
|
||
BOOL Enabled;
|
||
SAINFO* Info;
|
||
TCHAR* Key;
|
||
TCHAR* KeyEnd;
|
||
TCHAR* KeyList;
|
||
ULONG KeyValue;
|
||
TCHAR* Path;
|
||
TCHAR SectionName[32];
|
||
SASERVER* Server;
|
||
TRACE("RasLoadSharedAccessSettings");
|
||
|
||
//
|
||
// Allocate and initialize the settings-structure
|
||
//
|
||
|
||
Info = (SAINFO*)Malloc(sizeof(SAINFO));
|
||
if (!Info) { return NULL; }
|
||
|
||
InitializeListHead(&Info->ApplicationList);
|
||
InitializeListHead(&Info->ServerList);
|
||
|
||
//
|
||
// Read scope information from the registry
|
||
//
|
||
|
||
CsQueryScopeInformation(NULL, &Info->ScopeAddress, &Info->ScopeMask);
|
||
|
||
//
|
||
// Construct the path to the shared access information file,
|
||
// and read the index of 'application' sections.
|
||
// Each section should contain a valid application-description,
|
||
// for which we construct a corresponding 'SAAPPLICATION' entry
|
||
// in the application-list.
|
||
//
|
||
|
||
if (!(Path = LoadPath())) {
|
||
RasFreeSharedAccessSettings(Info);
|
||
return NULL;
|
||
}
|
||
|
||
wsprintf(SectionName, c_szSectionFormat, c_szContents, c_szApplication);
|
||
|
||
if (KeyList = LoadEntryList(SectionName, Path)) {
|
||
|
||
for (Key = KeyList; *Key; Key += lstrlen(Key) + 1) {
|
||
|
||
//
|
||
// Ensure the key is a valid hexadecimal integer,
|
||
// and read the 'Enabled' setting which is its value.
|
||
// N.B. if the entry is disabled and the caller only wants
|
||
// enabled entries, exclude this one.
|
||
//
|
||
|
||
KeyValue = _tcstoul(Key, &KeyEnd, 16);
|
||
if (*KeyEnd++ != TEXT('=')) {
|
||
continue;
|
||
} else if (!(Enabled = !!_ttol(KeyEnd)) && EnabledOnly) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Read in the corresponding 'Application.<key>' section.
|
||
//
|
||
|
||
Application = LoadApplication(KeyValue, Enabled, Path);
|
||
if (Application) {
|
||
InsertTailList(&Info->ApplicationList, &Application->Link);
|
||
}
|
||
}
|
||
|
||
Free(KeyList);
|
||
}
|
||
|
||
//
|
||
// Finally, read the index of 'server' sections, and read each section.
|
||
// Each section contains a server-description for which we construct
|
||
// a corresponding 'SASERVER' entry in the server-list.
|
||
//
|
||
|
||
wsprintf(SectionName, c_szSectionFormat, c_szContents, c_szServer);
|
||
|
||
if (KeyList = LoadEntryList(SectionName, Path)) {
|
||
|
||
for (Key = KeyList; *Key; Key += lstrlen(Key) + 1) {
|
||
|
||
//
|
||
// Ensure the key is a valid hexadecimal integer,
|
||
// and read the 'Enabled' setting which is its value.
|
||
// N.B. if the entry is disabled and the caller only wants
|
||
// enabled entries, exclude this one.
|
||
//
|
||
|
||
KeyValue = _tcstoul(Key, &KeyEnd, 16);
|
||
if (*KeyEnd++ != TEXT('=')) {
|
||
continue;
|
||
} else if (!(Enabled = !!_ttol(KeyEnd)) && EnabledOnly) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Read in the corresponding 'Server.<key>' section.
|
||
//
|
||
|
||
Server = LoadServer(KeyValue, Enabled, Path);
|
||
if (Server) {
|
||
InsertTailList(&Info->ServerList, &Server->Link);
|
||
}
|
||
}
|
||
|
||
Free(KeyList);
|
||
}
|
||
|
||
return Info;
|
||
|
||
} // RasLoadSharedAccessSettings
|
||
|
||
|
||
BOOL APIENTRY
|
||
RasSaveSharedAccessSettings(
|
||
IN SAINFO* Info
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Stores the shared access settings in 'Info' back into the local registry
|
||
from where the settings were read.
|
||
|
||
N.B. If 'Info' was loaded with the 'EnableOnly' flag, saving it back
|
||
will erase all disabled entries.
|
||
|
||
Arguments:
|
||
|
||
Info - supplies the settings to be saved
|
||
|
||
Return Value:
|
||
|
||
BOOL - TRUE if successful, FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
SAAPPLICATION* Application;
|
||
TCHAR Buffer[10];
|
||
PLIST_ENTRY Link;
|
||
TCHAR Key[10];
|
||
TCHAR* Path;
|
||
TCHAR SectionName[32];
|
||
SASERVER* Server;
|
||
|
||
TRACE("RasSaveSharedAccessSettings");
|
||
|
||
//
|
||
// First erase the existing file.
|
||
//
|
||
|
||
if (!(Path = LoadPath()) || CreateDirectoriesOnPath(Path, NULL)) {
|
||
Free0(Path);
|
||
return FALSE;
|
||
}
|
||
|
||
DeleteFile(Path);
|
||
|
||
//
|
||
// Now we reconstruct the file.
|
||
// We begin by saving each application entry, in the process building
|
||
// a content index of all the saved entries.
|
||
//
|
||
|
||
wsprintf(SectionName, c_szSectionFormat, c_szContents, c_szApplication);
|
||
|
||
for (Link = Info->ApplicationList.Flink; Link != &Info->ApplicationList;
|
||
Link = Link->Flink) {
|
||
Application = CONTAINING_RECORD(Link, SAAPPLICATION, Link);
|
||
if (SaveApplication(Application, Path)) {
|
||
wsprintf(Key, c_szKeyFormat, Application->Key);
|
||
_ltot(!!Application->Enabled, Buffer, 10);
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
Key,
|
||
Buffer,
|
||
Path
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Similarly, save each server entry, in the process building
|
||
// a content index of all the saved entries.
|
||
//
|
||
|
||
wsprintf(SectionName, c_szSectionFormat, c_szContents, c_szServer);
|
||
|
||
for (Link = Info->ServerList.Flink; Link != &Info->ServerList;
|
||
Link = Link->Flink) {
|
||
Server = CONTAINING_RECORD(Link, SASERVER, Link);
|
||
if (SaveServer(Info, Server, Path)) {
|
||
wsprintf(Key, c_szKeyFormat, Server->Key);
|
||
_ltot(!!Server->Enabled, Buffer, 10);
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
Key,
|
||
Buffer,
|
||
Path
|
||
);
|
||
}
|
||
}
|
||
|
||
Free(Path);
|
||
CsControlService(IPNATHLP_CONTROL_UPDATE_SETTINGS);
|
||
return TRUE;
|
||
} // RasSaveSharedAccessSettings
|
||
|
||
|
||
VOID APIENTRY
|
||
FreeSharedAccessApplication(
|
||
SAAPPLICATION* Application
|
||
)
|
||
{
|
||
PLIST_ENTRY Link;
|
||
SARESPONSE* Response;
|
||
while (!IsListEmpty(&Application->ResponseList)) {
|
||
Link = RemoveHeadList(&Application->ResponseList);
|
||
Response = CONTAINING_RECORD(Link, SARESPONSE, Link);
|
||
Free(Response);
|
||
}
|
||
Free0(Application->Title);
|
||
Free(Application);
|
||
}
|
||
|
||
|
||
VOID APIENTRY
|
||
FreeSharedAccessServer(
|
||
SASERVER* Server
|
||
)
|
||
{
|
||
Free0(Server->Title);
|
||
Free0(Server->InternalName);
|
||
Free(Server);
|
||
}
|
||
|
||
|
||
SAAPPLICATION*
|
||
LoadApplication(
|
||
ULONG KeyValue,
|
||
BOOL Enabled,
|
||
const TCHAR* Path
|
||
)
|
||
{
|
||
SAAPPLICATION* Application;
|
||
TCHAR* EntryList;
|
||
TCHAR Key[10];
|
||
TCHAR SectionName[32];
|
||
TCHAR* Value;
|
||
|
||
wsprintf(Key, c_szKeyFormat, KeyValue);
|
||
wsprintf(SectionName, c_szSectionFormat, c_szApplication, Key);
|
||
if (!(EntryList = LoadEntryList(SectionName, Path))) { return NULL; }
|
||
|
||
do {
|
||
|
||
//
|
||
// Allocate and initialize an 'application' entry.
|
||
//
|
||
|
||
Application = (SAAPPLICATION*)Malloc(sizeof(SAAPPLICATION));
|
||
if (!Application) { break; }
|
||
|
||
ZeroMemory(Application, sizeof(*Application));
|
||
InitializeListHead(&Application->ResponseList);
|
||
Application->Key = KeyValue;
|
||
Application->Enabled = Enabled;
|
||
|
||
//
|
||
// Read each required '<tag>=<value>' entry in the section.
|
||
// The tags required for an application are
|
||
// 'Title='
|
||
// 'Protocol='
|
||
// 'Port='
|
||
// The optional tags, at least one of which must be present, are
|
||
// 'TcpResponseList='
|
||
// 'UdpResponseList='
|
||
// The optional tags which may be absent are
|
||
// 'BuiltIn='
|
||
//
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagTitle);
|
||
if (!Value) { break; }
|
||
Application->Title = StrDup(Value);
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagProtocol);
|
||
if (!Value) { break; }
|
||
if (!Lstrcmpni(Value, c_szTCP, LSTRLEN(c_szTCP))) {
|
||
Application->Protocol = NAT_PROTOCOL_TCP;
|
||
} else if (!Lstrcmpni(Value, c_szUDP, LSTRLEN(c_szTCP))) {
|
||
Application->Protocol = NAT_PROTOCOL_UDP;
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagPort);
|
||
if (!Value || !(Application->Port = (USHORT)_ttol(Value))) { break; }
|
||
Application->Port = HTONS(Application->Port);
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagTcpResponseList);
|
||
if (Value) {
|
||
SharedAccessResponseStringToList(
|
||
NAT_PROTOCOL_TCP,
|
||
Value,
|
||
&Application->ResponseList
|
||
);
|
||
}
|
||
Value = QueryEntryList(EntryList, c_szTagUdpResponseList);
|
||
if (Value) {
|
||
SharedAccessResponseStringToList(
|
||
NAT_PROTOCOL_UDP,
|
||
Value,
|
||
&Application->ResponseList
|
||
);
|
||
}
|
||
if (IsListEmpty(&Application->ResponseList)) { break; }
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagBuiltIn);
|
||
if (Value) {
|
||
Application->BuiltIn = _ttol(Value) ? TRUE : FALSE;
|
||
} else {
|
||
Application->BuiltIn = FALSE;
|
||
}
|
||
|
||
//
|
||
// The entry was loaded successfully.
|
||
//
|
||
|
||
Free(EntryList);
|
||
return Application;
|
||
|
||
} while (FALSE);
|
||
|
||
//
|
||
// Something went wrong.
|
||
//
|
||
|
||
if (Application) { FreeSharedAccessApplication(Application); }
|
||
Free(EntryList);
|
||
return NULL;
|
||
}
|
||
|
||
|
||
TCHAR*
|
||
LoadEntryList(
|
||
const TCHAR* Section,
|
||
const TCHAR* Path
|
||
)
|
||
{
|
||
CHAR* BufferA = NULL;
|
||
ULONG Length;
|
||
CHAR* PathA = NULL;
|
||
CHAR* SectionA = NULL;
|
||
ULONG Size;
|
||
CHAR* Source;
|
||
TCHAR* Target;
|
||
TCHAR* BufferW = NULL;
|
||
|
||
if (!(SectionA = StrDupAFromT(Section))) {
|
||
return NULL;
|
||
}
|
||
if (!(PathA = StrDupAFromTAnsi(Path))) {
|
||
Free(SectionA);
|
||
return NULL;
|
||
}
|
||
for (BufferA = NULL, Size = MAX_PATH; ; Size += MAX_PATH, Free(BufferA)) {
|
||
|
||
BufferA = (CHAR*)Malloc(Size);
|
||
if (!BufferA) {
|
||
break;
|
||
}
|
||
|
||
if (GetPrivateProfileSectionA(SectionA, BufferA, Size, PathA)
|
||
== Size-2) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Convert each string in the buffer from UTF8 format to Unicode.
|
||
// The conversion will result in at most 'Size' Unicode characters,
|
||
// and fewer if 2- or 3-byte UTF8 sequences are present in the
|
||
// source buffer.
|
||
//
|
||
|
||
BufferW = (TCHAR*)Malloc(Size * sizeof(TCHAR));
|
||
if (!BufferW) {
|
||
break;
|
||
}
|
||
Target = BufferW;
|
||
for (Source = BufferA; *Source; Source += lstrlenA(Source) + 1) {
|
||
if (StrCpyWFromA(Target, Source, Size) != NO_ERROR) {
|
||
break;
|
||
}
|
||
Length = lstrlen(Target) + 1;
|
||
Target += Length;
|
||
Size -= Length;
|
||
}
|
||
if (*Source) { break; }
|
||
Free(BufferA);
|
||
Free(PathA);
|
||
Free(SectionA);
|
||
return BufferW;
|
||
}
|
||
Free0(BufferW);
|
||
Free0(BufferA);
|
||
Free0(PathA);
|
||
Free0(SectionA);
|
||
return NULL;
|
||
}
|
||
|
||
|
||
TCHAR*
|
||
LoadPath(
|
||
VOID
|
||
)
|
||
{
|
||
TCHAR* Path;
|
||
Path =
|
||
(TCHAR*)Malloc(
|
||
(MAX_PATH + lstrlen(c_szSharedAccessIni) + 1) * sizeof(TCHAR)
|
||
);
|
||
if (!Path || !GetPhonebookDirectory(PBM_System, Path)) {
|
||
Free0(Path);
|
||
return NULL;
|
||
}
|
||
|
||
lstrcat(Path, c_szSharedAccessIni);
|
||
return Path;
|
||
}
|
||
|
||
|
||
SASERVER*
|
||
LoadServer(
|
||
ULONG KeyValue,
|
||
BOOL Enabled,
|
||
const TCHAR* Path
|
||
)
|
||
{
|
||
SASERVER* Server;
|
||
TCHAR* EntryList;
|
||
TCHAR Key[10];
|
||
TCHAR SectionName[32];
|
||
TCHAR* Value;
|
||
|
||
wsprintf(Key, c_szKeyFormat, KeyValue);
|
||
wsprintf(SectionName, c_szSectionFormat, c_szServer, Key);
|
||
if (!(EntryList = LoadEntryList(SectionName, Path))) { return NULL; }
|
||
|
||
do {
|
||
|
||
//
|
||
// Allocate and initialize a 'server' entry.
|
||
//
|
||
|
||
Server = (SASERVER*)Malloc(sizeof(SASERVER));
|
||
if (!Server) { break; }
|
||
|
||
ZeroMemory(Server, sizeof(*Server));
|
||
Server->Key = KeyValue;
|
||
Server->Enabled = Enabled;
|
||
|
||
//
|
||
// Read each required '<tag>=<value>' entry in the section.
|
||
// The tags required for a server are
|
||
// 'Title='
|
||
// 'Protocol='
|
||
// 'Port='
|
||
// 'InternalPort='
|
||
// The optional tags which may be absent are
|
||
// 'BuiltIn='
|
||
// 'InternalName='
|
||
// 'ReservedAddress='
|
||
// The 'InternalName=' and 'ReservedAddress=' tags may only be absent
|
||
// if 'BuiltIn' is set, in which case the entry is disabled.
|
||
//
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagTitle);
|
||
if (!Value) { break; }
|
||
Server->Title = StrDup(Value);
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagProtocol);
|
||
if (!Value) { break; }
|
||
if (!Lstrcmpni(Value, c_szTCP, LSTRLEN(c_szTCP))) {
|
||
Server->Protocol = NAT_PROTOCOL_TCP;
|
||
} else if (!Lstrcmpni(Value, c_szUDP, LSTRLEN(c_szTCP))) {
|
||
Server->Protocol = NAT_PROTOCOL_UDP;
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagPort);
|
||
if (!Value || !(Server->Port = (USHORT)_ttol(Value))) { break; }
|
||
Server->Port = HTONS(Server->Port);
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagInternalPort);
|
||
if (!Value || !(Server->InternalPort = (USHORT)_ttol(Value))) { break; }
|
||
Server->InternalPort = HTONS(Server->InternalPort);
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagBuiltIn);
|
||
if (Value) {
|
||
Server->BuiltIn = _ttol(Value) ? TRUE : FALSE;
|
||
} else {
|
||
Server->BuiltIn = FALSE;
|
||
}
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagInternalName);
|
||
if (!Value || !lstrlen(Value)) {
|
||
if (!Server->BuiltIn) {
|
||
break;
|
||
} else {
|
||
Server->InternalName = NULL;
|
||
Server->Enabled = FALSE;
|
||
}
|
||
} else {
|
||
Server->InternalName = StrDup(Value);
|
||
}
|
||
|
||
Value = QueryEntryList(EntryList, c_szTagReservedAddress);
|
||
if (!Value || !lstrlen(Value)) {
|
||
if (!Server->BuiltIn) {
|
||
break;
|
||
} else {
|
||
Server->ReservedAddress = INADDR_NONE;
|
||
Server->Enabled = FALSE;
|
||
}
|
||
} else {
|
||
Server->ReservedAddress = IpPszToHostAddr(Value);
|
||
if (Server->ReservedAddress == INADDR_NONE && !Server->BuiltIn) {
|
||
break;
|
||
}
|
||
Server->ReservedAddress = HTONL(Server->ReservedAddress);
|
||
}
|
||
|
||
//
|
||
// The entry was loaded successfully.
|
||
//
|
||
|
||
Free(EntryList);
|
||
return Server;
|
||
|
||
} while (FALSE);
|
||
|
||
//
|
||
// Something went wrong.
|
||
//
|
||
|
||
if (Server) { FreeSharedAccessServer(Server); }
|
||
Free(EntryList);
|
||
return NULL;
|
||
}
|
||
|
||
|
||
LONG
|
||
Lstrcmpni(
|
||
const TCHAR* String1,
|
||
const TCHAR* String2,
|
||
LONG Length
|
||
)
|
||
{
|
||
return
|
||
CSTR_EQUAL -
|
||
CompareString(
|
||
LOCALE_SYSTEM_DEFAULT,
|
||
NORM_IGNORECASE,
|
||
String1,
|
||
Length,
|
||
String2,
|
||
Length
|
||
);
|
||
}
|
||
|
||
|
||
TCHAR*
|
||
QueryEntryList(
|
||
const TCHAR* EntryList,
|
||
const TCHAR* Tag
|
||
)
|
||
{
|
||
TCHAR* Entry;
|
||
ULONG TagLength = lstrlen(Tag);
|
||
for (Entry = (TCHAR*)EntryList; *Entry; Entry += lstrlen(Entry) + 1) {
|
||
if (Entry[0] == Tag[0] && !Lstrcmpni(Tag, Entry, TagLength)) {
|
||
return Entry + TagLength;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
|
||
BOOL
|
||
SaveApplication(
|
||
SAAPPLICATION* Application,
|
||
const TCHAR* Path
|
||
)
|
||
{
|
||
TCHAR Buffer[32];
|
||
ULONG Length;
|
||
PLIST_ENTRY Link;
|
||
SARESPONSE* Response;
|
||
TCHAR SectionName[32];
|
||
TCHAR* Value;
|
||
|
||
wsprintf(Buffer, c_szKeyFormat, Application->Key);
|
||
wsprintf(SectionName, c_szSectionFormat, c_szApplication, Buffer);
|
||
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szTitle,
|
||
Application->Title,
|
||
Path
|
||
);
|
||
|
||
if (Application->Protocol == NAT_PROTOCOL_TCP) {
|
||
Value = (TCHAR*)c_szTCP;
|
||
} else if (Application->Protocol == NAT_PROTOCOL_UDP) {
|
||
Value = (TCHAR*)c_szUDP;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szProtocol,
|
||
Value,
|
||
Path
|
||
);
|
||
|
||
_ltot(NTOHS(Application->Port), Buffer, 10);
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szPort,
|
||
Buffer,
|
||
Path
|
||
);
|
||
|
||
Value = SharedAccessResponseListToString(&Application->ResponseList, NAT_PROTOCOL_TCP);
|
||
if (Value) {
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szTcpResponseList,
|
||
Value,
|
||
Path
|
||
);
|
||
Free(Value);
|
||
}
|
||
|
||
Value = SharedAccessResponseListToString(&Application->ResponseList, NAT_PROTOCOL_UDP);
|
||
if (Value) {
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szUdpResponseList,
|
||
Value,
|
||
Path
|
||
);
|
||
Free(Value);
|
||
}
|
||
|
||
_ltot(Application->BuiltIn, Buffer, 10);
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szBuiltIn,
|
||
Buffer,
|
||
Path
|
||
);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
SaveServer(
|
||
SAINFO* Info,
|
||
SASERVER* Server,
|
||
const TCHAR* Path
|
||
)
|
||
{
|
||
TCHAR Buffer[32];
|
||
ULONG ReservedAddress;
|
||
TCHAR SectionName[32];
|
||
TCHAR* Value;
|
||
|
||
wsprintf(Buffer, c_szKeyFormat, Server->Key);
|
||
wsprintf(SectionName, c_szSectionFormat, c_szServer, Buffer);
|
||
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szTitle,
|
||
Server->Title,
|
||
Path
|
||
);
|
||
|
||
if (Server->Protocol == NAT_PROTOCOL_TCP) {
|
||
Value = (TCHAR*)c_szTCP;
|
||
} else if (Server->Protocol == NAT_PROTOCOL_UDP) {
|
||
Value = (TCHAR*)c_szUDP;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szProtocol,
|
||
Value,
|
||
Path
|
||
);
|
||
|
||
_ltot(NTOHS(Server->Port), Buffer, 10);
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szPort,
|
||
Buffer,
|
||
Path
|
||
);
|
||
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szInternalName,
|
||
Server->InternalName,
|
||
Path
|
||
);
|
||
|
||
_ltot(NTOHS(Server->InternalPort), Buffer, 10);
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szInternalPort,
|
||
Buffer,
|
||
Path
|
||
);
|
||
|
||
if (Server->InternalName && lstrlen(Server->InternalName)) {
|
||
ReservedAddress = IpPszToHostAddr(Server->InternalName);
|
||
if (ReservedAddress != INADDR_NONE) {
|
||
Server->ReservedAddress = HTONL(ReservedAddress);
|
||
}
|
||
if (Server->ReservedAddress == INADDR_NONE) {
|
||
SASERVER* Entry;
|
||
ULONG Index;
|
||
PLIST_ENTRY Link;
|
||
ULONG ScopeLength;
|
||
for (Link = Info->ServerList.Flink; Link != &Info->ServerList;
|
||
Link = Link->Flink) {
|
||
Entry = CONTAINING_RECORD(Link, SASERVER, Link);
|
||
if (Entry != Server &&
|
||
Entry->ReservedAddress &&
|
||
Entry->ReservedAddress != INADDR_NONE &&
|
||
lstrcmpi(Entry->InternalName, Server->InternalName) == 0) {
|
||
Server->ReservedAddress = Entry->ReservedAddress;
|
||
break;
|
||
}
|
||
}
|
||
if (Server->ReservedAddress == INADDR_NONE) {
|
||
ScopeLength = NTOHL(~Info->ScopeMask);
|
||
for (Index = 1; Index < ScopeLength - 1; Index++) {
|
||
ReservedAddress =
|
||
(Info->ScopeAddress & Info->ScopeMask) | HTONL(Index);
|
||
if (ReservedAddress == Info->ScopeAddress) { continue; }
|
||
for (Link = Info->ServerList.Flink;
|
||
Link != &Info->ServerList; Link = Link->Flink) {
|
||
Entry = CONTAINING_RECORD(Link, SASERVER, Link);
|
||
if (Entry->ReservedAddress == ReservedAddress) {
|
||
break;
|
||
}
|
||
}
|
||
if (Link == &Info->ServerList) { break; }
|
||
}
|
||
if (Index > ScopeLength) { return FALSE; }
|
||
Server->ReservedAddress = ReservedAddress;
|
||
}
|
||
}
|
||
|
||
IpHostAddrToPsz(NTOHL(Server->ReservedAddress), Buffer);
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szReservedAddress,
|
||
Buffer,
|
||
Path
|
||
);
|
||
}
|
||
|
||
_ltot(Server->BuiltIn, Buffer, 10);
|
||
WritePrivateProfileStringUTF8(
|
||
SectionName,
|
||
c_szBuiltIn,
|
||
Buffer,
|
||
Path
|
||
);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
TCHAR* APIENTRY
|
||
SharedAccessResponseListToString(
|
||
PLIST_ENTRY ResponseList,
|
||
UCHAR Protocol
|
||
)
|
||
{
|
||
TCHAR Buffer[LSTRLEN(c_szMaxResponseEntry)];
|
||
ULONG Length;
|
||
PLIST_ENTRY Link;
|
||
SARESPONSE* Response;
|
||
TCHAR* Value;
|
||
|
||
Length = 2;
|
||
for (Link = ResponseList->Flink;
|
||
Link != ResponseList; Link = Link->Flink) {
|
||
Response = CONTAINING_RECORD(Link, SARESPONSE, Link);
|
||
if (Response->Protocol != Protocol) { continue; }
|
||
Length += LSTRLEN(c_szMaxResponseEntry);
|
||
}
|
||
|
||
if (Length == 2) { return NULL; }
|
||
|
||
Value = (TCHAR*)Malloc(Length * sizeof(TCHAR));
|
||
if (!Value) { return NULL; }
|
||
|
||
Value[0] = TEXT('\0');
|
||
for (Link = ResponseList->Flink;
|
||
Link != ResponseList; Link = Link->Flink) {
|
||
Response = CONTAINING_RECORD(Link, SARESPONSE, Link);
|
||
if (Response->Protocol != Protocol) { continue; }
|
||
if (Value[0] != TEXT('\0')) {
|
||
lstrcat(Value, TEXT(","));
|
||
}
|
||
if (Response->StartPort == Response->EndPort) {
|
||
wsprintf(
|
||
Buffer,
|
||
c_szResponseFormat1,
|
||
NTOHS(Response->StartPort)
|
||
);
|
||
} else {
|
||
wsprintf(
|
||
Buffer,
|
||
c_szResponseFormat2,
|
||
NTOHS(Response->StartPort),
|
||
NTOHS(Response->EndPort)
|
||
);
|
||
}
|
||
lstrcat(Value, Buffer);
|
||
}
|
||
return Value;
|
||
}
|
||
|
||
|
||
BOOL APIENTRY
|
||
SharedAccessResponseStringToList(
|
||
UCHAR Protocol,
|
||
TCHAR* Value,
|
||
PLIST_ENTRY ListHead
|
||
)
|
||
{
|
||
TCHAR* Endp;
|
||
ULONG EndPort;
|
||
LONG Length;
|
||
SARESPONSE* Response;
|
||
ULONG StartPort;
|
||
|
||
while (*Value) {
|
||
//
|
||
// Read either a single port or a range of ports.
|
||
//
|
||
if (!(StartPort = _tcstoul(Value, &Endp, 10))) {
|
||
return FALSE;
|
||
} else if (StartPort > USHRT_MAX) {
|
||
return FALSE;
|
||
}
|
||
while(*Endp == ' ') Endp++; // consume whitespace
|
||
if (!*Endp || *Endp == ',') {
|
||
EndPort = StartPort;
|
||
Value = (!*Endp ? Endp : Endp + 1);
|
||
} else if (*Endp != '-') {
|
||
return FALSE;
|
||
} else if (!(EndPort = _tcstoul(++Endp, &Value, 10))) {
|
||
return FALSE;
|
||
} else if (EndPort > USHRT_MAX) {
|
||
return FALSE;
|
||
} else if (EndPort < StartPort) {
|
||
return FALSE;
|
||
} else if (*Value && *Value++ != ',') {
|
||
return FALSE;
|
||
}
|
||
//
|
||
// Allocate and append another response entry
|
||
//
|
||
Response = (SARESPONSE*)Malloc(sizeof(SARESPONSE));
|
||
if (!Response) { return FALSE; }
|
||
Response->Protocol = Protocol;
|
||
Response->StartPort = HTONS((USHORT)StartPort);
|
||
Response->EndPort = HTONS((USHORT)EndPort);
|
||
InsertTailList(ListHead, &Response->Link);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
#if 0
|
||
|
||
|
||
BOOL
|
||
WritePrivateProfileStringUTF8(
|
||
const TCHAR* Section,
|
||
const TCHAR* Key,
|
||
const TCHAR* Value,
|
||
const TCHAR* Path
|
||
)
|
||
{
|
||
CHAR* KeyA;
|
||
CHAR* PathA;
|
||
CHAR* SectionA;
|
||
BOOL Succeeded;
|
||
CHAR* ValueA = NULL;
|
||
|
||
if (!(SectionA = StrDupAFromT(Section))) {
|
||
Succeeded = FALSE;
|
||
} else {
|
||
if (!(KeyA = StrDupAFromT(Key))) {
|
||
Succeeded = FALSE;
|
||
} else {
|
||
if (Value && !(ValueA = StrDupAFromT(Value))) {
|
||
Succeeded = FALSE;
|
||
} else {
|
||
if (!(PathA = StrDupAFromTAnsi(Path))) {
|
||
Succeeded = FALSE;
|
||
} else {
|
||
Succeeded =
|
||
WritePrivateProfileStringA(
|
||
SectionA,
|
||
KeyA,
|
||
ValueA,
|
||
PathA
|
||
);
|
||
Free(PathA);
|
||
}
|
||
Free0(ValueA);
|
||
}
|
||
Free(KeyA);
|
||
}
|
||
Free(SectionA);
|
||
}
|
||
return Succeeded;
|
||
}
|
||
|
||
#endif
|