windows-nt/Source/XPSP1/NT/net/dhcp/server/exim/mmfile.c
2020-09-26 16:20:57 +08:00

1291 lines
31 KiB
C

/*++
Copyright (C) 2000 Microsoft Corporation
Module Name:
mmfile.c
Abstract;
This file contains code to read/write MM data structures
from/to internal file format.. code is nearly ripped off of
server\dbconfig.c
--*/
#include <precomp.h>
typedef struct _DB_CREATE_CONTEXT {
IN ULONG Index;
IN PM_SERVER Server;
IN PM_CLASSDEF UserClass, VendorClass;
IN PM_SUBNET Subnet;
IN PM_RESERVATION Reservation;
} DB_CREATE_CONTEXT, *PDB_CREATE_CONTEXT;
//
// types of records
//
enum {
DBCFG_CLASS,
DBCFG_OPT,
DBCFG_OPTDEF,
DBCFG_SCOPE,
DBCFG_MSCOPE,
DBCFG_RANGE,
DBCFG_EXCL,
DBCFG_RESERVATION,
DBCFG_END
};
//
// attributes/fields
//
enum {
DBCFG_INDEX,
DBCFG_TYPE,
DBCFG_SUBTYPE,
DBCFG_FLAGS,
DBCFG_NAME,
DBCFG_COMMENT,
DBCFG_INFO,
DBCFG_OPTION_ID,
DBCFG_OPTION_USER,
DBCFG_OPTION_VENDOR,
DBCFG_IPADDRESS,
DBCFG_MASK,
DBCFG_SUPERSCOPE,
DBCFG_MSCOPEID,
DBCFG_MSCOPELANG,
DBCFG_MSCOPETTL,
DBCFG_MSCOPE_EXPIRY,
DBCFG_RANGE_START,
DBCFG_RANGE_END,
DBCFG_RANGE_MASK,
DBCFG_BOOTP_ALLOCATED,
DBCFG_BOOTP_MAX,
DBCFG_LAST_COLUMN
};
typedef struct _DBCFG_ENTRY {
ULONG Bitmasks; // indicates which of the fields below is present
ULONG Index;
ULONG Type, SubType, Flags;
LPWSTR Name, Comment;
PUCHAR Info;
ULONG OptionId;
LPWSTR UserClass, VendorClass;
ULONG IpAddress, Mask;
LPWSTR SuperScope;
ULONG MscopeId;
LPWSTR MscopeLang;
ULONG Ttl;
FILETIME ExpiryTime;
ULONG RangeStart, RangeEnd, RangeMask;
ULONG BootpAllocated, BootpMax;
ULONG InfoSize;
PVOID Buf;
} DBCFG_ENTRY, *PDBCFG_ENTRY;
typedef struct _DBCFG_MAP {
DWORD Offset, Size;
} DBCFG_MAP;
DBCFG_MAP EntryMap[] = {
FIELD_OFFSET(DBCFG_ENTRY,Index), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,Type), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,SubType), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,Flags), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,Name), 0,
FIELD_OFFSET(DBCFG_ENTRY,Comment), 0,
FIELD_OFFSET(DBCFG_ENTRY,Info), 0,
FIELD_OFFSET(DBCFG_ENTRY,OptionId), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,UserClass), 0,
FIELD_OFFSET(DBCFG_ENTRY,VendorClass), 0,
FIELD_OFFSET(DBCFG_ENTRY,IpAddress), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,Mask), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,SuperScope), 0,
FIELD_OFFSET(DBCFG_ENTRY,MscopeId), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,MscopeLang), 0,
FIELD_OFFSET(DBCFG_ENTRY,Ttl), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,ExpiryTime), sizeof(FILETIME),
FIELD_OFFSET(DBCFG_ENTRY,RangeStart), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,RangeEnd), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,RangeMask), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,BootpAllocated), sizeof(DWORD),
FIELD_OFFSET(DBCFG_ENTRY,BootpMax), sizeof(DWORD)
};
DWORD Bitmasks[] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
0x010000, 0x020000, 0x040000, 0x080000, 0x100000, 0x200000,
0x400000, 0x80000,
};
DWORD
CreateDbEntry(
IN PDBCFG_ENTRY Entry
)
{
DWORD Error, Size, i, Offset;
PVOID Data;
WORD Buffer[4096];
Offset = 0;
for( i = 0; i < DBCFG_LAST_COLUMN; i ++ ) {
if( (Entry->Bitmasks & Bitmasks[i]) == 0 ) {
continue;
}
Size = EntryMap[i].Size;
Data = EntryMap[i].Offset + (LPBYTE)Entry;
if( i == DBCFG_INFO ) {
//
// Skip info -- it is added at end
//
continue;
} else if( 0 == Size ) {
//
// Calculate the size of the string
//
Data = *(LPWSTR *)Data;
if( NULL != Data ) Size = sizeof(WCHAR)*(
1 + wcslen(Data));
}
if( 0 == Size ) continue;
Buffer[Offset++] = (WORD)i;
Buffer[Offset++] = (WORD)Size;
memcpy(&Buffer[Offset], Data, Size);
Offset += (Size + sizeof(WORD) - 1 )/sizeof(WORD);
}
//
// add info at the end.
//
i = DBCFG_INFO;
if( Entry->Bitmasks & Bitmasks[i]) {
Size = EntryMap[i].Size;
Data = EntryMap[i].Offset + (LPBYTE)Entry;
Data = *(PUCHAR *)Data;
if( NULL != Data ) Size = Entry->InfoSize;
if( 0 != Size ) {
Buffer[Offset++] = (WORD)i;
Buffer[Offset++] = (WORD)Size;
memcpy(&Buffer[Offset], Data, Size);
Offset += (Size + sizeof(WORD) - 1 )/sizeof(WORD);
}
}
Buffer[Offset++] = DBCFG_LAST_COLUMN+1;
Buffer[Offset++] = 0;
//
// Write the record onto file
//
return AddRecordNoSize( (LPBYTE)Buffer, Offset*sizeof(WORD));
}
DWORD
CreateClassEntry(
IN ULONG Index,
IN PM_CLASSDEF Class
)
{
DBCFG_ENTRY Entry;
//
// IsVendor, Type, Name, Comment, nBytes, ActualBytes
//
ZeroMemory(&Entry, sizeof(Entry));
Entry.Bitmasks = (
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
Bitmasks[DBCFG_SUBTYPE] |
Bitmasks[DBCFG_FLAGS] | Bitmasks[DBCFG_SUBTYPE] |
Bitmasks[DBCFG_NAME] | Bitmasks[DBCFG_COMMENT] |
Bitmasks[DBCFG_INFO] );
Entry.Index = Index;
Entry.Type = DBCFG_CLASS;
Entry.Flags = Class->IsVendor;
Entry.SubType = Class->Type;
Entry.Name = Class->Name;
Entry.Comment = Class->Comment;
Entry.Info = Class->ActualBytes;
Entry.InfoSize = Class->nBytes;
return CreateDbEntry( &Entry );
}
DWORD
CreateOptDefEntry(
IN ULONG Index,
IN PM_OPTDEF OptDef,
IN PM_CLASSDEF UserClass,
IN PM_CLASSDEF VendorClass
)
{
DBCFG_ENTRY Entry;
//
// OptId, Type, OptName, OptComment, OptVal, OptValLen,
// User, Vendor
//
ZeroMemory(&Entry, sizeof(Entry));
Entry.Bitmasks = (
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
Bitmasks[DBCFG_SUBTYPE] | Bitmasks[DBCFG_OPTION_ID] |
Bitmasks[DBCFG_NAME] | Bitmasks[DBCFG_COMMENT] |
Bitmasks[DBCFG_INFO] | Bitmasks[DBCFG_OPTION_USER] |
Bitmasks[DBCFG_OPTION_VENDOR] );
Entry.Index = Index;
Entry.Type = DBCFG_OPTDEF;
Entry.OptionId = OptDef->OptId;
Entry.SubType = OptDef->Type;
Entry.Name = OptDef->OptName;
Entry.Comment = OptDef->OptComment;
Entry.Info = OptDef->OptVal;
Entry.InfoSize = OptDef->OptValLen;
if( UserClass) Entry.UserClass = UserClass->Name;
if( VendorClass) Entry.VendorClass = VendorClass->Name;
return CreateDbEntry( &Entry );
}
DWORD
CreateOptionEntry(
IN ULONG Index,
IN PM_OPTION Option,
IN PM_CLASSDEF UserClass,
IN PM_CLASSDEF VendorClass,
IN PM_SUBNET Subnet,
IN PM_RESERVATION Reservation
)
{
DBCFG_ENTRY Entry;
//
// OptId, Len, Val, User, Vendor
//
ZeroMemory(&Entry, sizeof(Entry));
Entry.Bitmasks = (
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
Bitmasks[DBCFG_OPTION_ID] | Bitmasks[DBCFG_INFO] |
Bitmasks[DBCFG_OPTION_USER] |
Bitmasks[DBCFG_OPTION_VENDOR] );
if( Reservation ) {
Entry.Bitmasks |= Bitmasks[DBCFG_IPADDRESS];
Entry.IpAddress = Reservation->Address;
} else if( Subnet && Subnet->fSubnet ) {
Entry.Bitmasks |= Bitmasks[DBCFG_IPADDRESS];
Entry.IpAddress = Subnet->Address;
} else if( Subnet && !Subnet->fSubnet ) {
Entry.Bitmasks |= Bitmasks[DBCFG_MSCOPEID];
Entry.MscopeId = Subnet->MScopeId;
}
Entry.Index = Index;
Entry.Type = DBCFG_OPT;
Entry.OptionId = Option->OptId;
Entry.Info = Option->Val;
Entry.InfoSize = Option->Len;
if( UserClass) Entry.UserClass = UserClass->Name;
if( VendorClass) Entry.VendorClass = VendorClass->Name;
return CreateDbEntry( &Entry );
}
DWORD
CreateScopeEntry(
IN ULONG Index,
IN PM_SUBNET Subnet,
IN PM_SSCOPE SScope
)
{
DBCFG_ENTRY Entry;
//
// State, Policy, ExpiryTime, Name, Description
//
ZeroMemory(&Entry, sizeof(Entry));
Entry.Bitmasks = (
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
Bitmasks[DBCFG_SUBTYPE] | Bitmasks[DBCFG_FLAGS] |
Bitmasks[DBCFG_NAME] | Bitmasks[DBCFG_COMMENT] );
if( Subnet->fSubnet ) {
Entry.Bitmasks |= (
Bitmasks[DBCFG_IPADDRESS] | Bitmasks[DBCFG_MASK] |
Bitmasks[DBCFG_SUPERSCOPE] );
Entry.IpAddress = Subnet->Address;
Entry.Mask = Subnet->Mask;
if( SScope ) Entry.SuperScope = SScope->Name;
} else {
Entry.Bitmasks |= (
Bitmasks[DBCFG_MSCOPEID] | Bitmasks[DBCFG_MSCOPETTL] |
Bitmasks[DBCFG_MSCOPELANG] |
Bitmasks[DBCFG_MSCOPE_EXPIRY] );
Entry.MscopeId = Subnet->MScopeId;
Entry.Ttl = Subnet->TTL;
Entry.MscopeLang = Subnet->LangTag;
Entry.ExpiryTime = *(FILETIME *)&Subnet->ExpiryTime;
}
Entry.Index = Index;
Entry.Type = Subnet->fSubnet ? DBCFG_SCOPE : DBCFG_MSCOPE ;
Entry.SubType = Subnet->State;
Entry.Flags = Subnet->Policy;
Entry.Name = Subnet->Name;
Entry.Comment = Subnet->Description;
return CreateDbEntry( &Entry );
}
DWORD
CreateRangeEntry(
IN ULONG Index,
IN PM_RANGE Range,
IN PM_SUBNET Subnet
)
{
DBCFG_ENTRY Entry;
//
// Start, End, Mask, State, BootpAllocated, MaxBootpAllowed
//
ZeroMemory(&Entry, sizeof(Entry));
Entry.Bitmasks = (
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
Bitmasks[DBCFG_RANGE_START] | Bitmasks[DBCFG_RANGE_END] |
Bitmasks[DBCFG_RANGE_MASK] | Bitmasks[DBCFG_FLAGS] |
Bitmasks[DBCFG_BOOTP_ALLOCATED] | Bitmasks[DBCFG_BOOTP_MAX] );
if( Subnet->fSubnet ) {
Entry.Bitmasks |= Bitmasks[DBCFG_IPADDRESS];
Entry.IpAddress = Subnet->Address;
} else {
Entry.Bitmasks |= Bitmasks[DBCFG_MSCOPEID];
Entry.MscopeId = Subnet->MScopeId;
}
Entry.Index = Index;
Entry.Type = DBCFG_RANGE;
Entry.RangeStart = Range->Start;
Entry.RangeEnd = Range->End;
Entry.RangeMask = Range->Mask;
Entry.Flags = Range->State;
Entry.BootpAllocated = Range->BootpAllocated;
Entry.BootpMax = Range->MaxBootpAllowed;
return CreateDbEntry( &Entry );
}
DWORD
CreateExclEntry(
IN ULONG Index,
IN PM_EXCL Excl,
IN PM_SUBNET Subnet
)
{
DBCFG_ENTRY Entry;
//
// Start, End
//
ZeroMemory(&Entry, sizeof(Entry));
Entry.Bitmasks = (
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
Bitmasks[DBCFG_RANGE_START] | Bitmasks[DBCFG_RANGE_END] );
if( Subnet->fSubnet ) {
Entry.Bitmasks |= Bitmasks[DBCFG_IPADDRESS];
Entry.IpAddress = Subnet->Address;
} else {
Entry.Bitmasks |= Bitmasks[DBCFG_MSCOPEID];
Entry.MscopeId = Subnet->MScopeId;
}
Entry.Index = Index;
Entry.Type = DBCFG_EXCL;
Entry.RangeStart = Excl->Start;
Entry.RangeEnd = Excl->End;
return CreateDbEntry( &Entry );
}
DWORD
CreateReservationEntry(
IN ULONG Index,
IN PM_RESERVATION Reservation
)
{
DBCFG_ENTRY Entry;
//
// Address, Flags, nBytes, ClientUID
//
ZeroMemory(&Entry, sizeof(Entry));
Entry.Bitmasks = (
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] |
Bitmasks[DBCFG_IPADDRESS] | Bitmasks[DBCFG_INFO] |
Bitmasks[DBCFG_FLAGS] );
Entry.Index = Index;
Entry.Type = DBCFG_RESERVATION;
Entry.IpAddress = Reservation->Address;
Entry.Flags = Reservation->Flags;
Entry.Info = Reservation->ClientUID;
Entry.InfoSize = Reservation->nBytes;
return CreateDbEntry( &Entry );
}
DWORD
IterateArrayWithDbCreateRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PARRAY Array,
IN DWORD (*Routine)(
IN PDB_CREATE_CONTEXT Ctxt,
IN PVOID ArrayElement
)
)
{
ARRAY_LOCATION Loc;
DWORD Error;
PVOID Element;
Error = MemArrayInitLoc( Array, &Loc );
while( NO_ERROR == Error ) {
Error = MemArrayGetElement(
Array, &Loc, &Element );
ASSERT( NO_ERROR == Error && NULL != Element );
Ctxt->Index ++;
Error = Routine( Ctxt, Element );
if( NO_ERROR != Error ) return Error;
Error = MemArrayNextLoc( Array, &Loc );
}
if( ERROR_FILE_NOT_FOUND == Error ) return NO_ERROR;
return Error;
}
DWORD
DbCreateClassRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_CLASSDEF Class
)
{
return CreateClassEntry( Ctxt->Index, Class );
}
DWORD
DbCreateOptDefRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_OPTDEF OptDef
)
{
return CreateOptDefEntry(
Ctxt->Index, OptDef, Ctxt->UserClass,
Ctxt->VendorClass );
}
DWORD
DbCreateOptClassDefRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_OPTCLASSDEFL_ONE OptClassDef
)
{
DWORD Error;
if( 0 == MemArraySize(&OptClassDef->OptDefList.OptDefArray) ) {
return NO_ERROR;
}
if( 0 == OptClassDef->ClassId ) {
Ctxt->UserClass = NULL;
} else {
Error = MemServerGetClassDef(
Ctxt->Server, OptClassDef->ClassId, NULL, 0, NULL,
&Ctxt->UserClass );
ASSERT( NO_ERROR == Error );
if( NO_ERROR != Error ) return Error;
}
if( 0 == OptClassDef->VendorId ) {
Ctxt->VendorClass = NULL;
} else {
Error = MemServerGetClassDef(
Ctxt->Server, OptClassDef->VendorId, NULL, 0, NULL,
&Ctxt->VendorClass );
ASSERT( NO_ERROR == Error );
if( NO_ERROR != Error ) return Error;
}
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &OptClassDef->OptDefList.OptDefArray,
DbCreateOptDefRoutine );
return Error;
}
DWORD
DbCreateOptionRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_OPTION Option
)
{
return CreateOptionEntry(
Ctxt->Index, Option, Ctxt->UserClass,
Ctxt->VendorClass, Ctxt->Subnet, Ctxt->Reservation );
}
DWORD
DbCreateOptListRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_ONECLASS_OPTLIST OptList
)
{
DWORD Error;
if( 0 == MemArraySize(&OptList->OptList) ) {
return NO_ERROR;
}
if( 0 == OptList->ClassId ) {
Ctxt->UserClass = NULL;
} else {
Error = MemServerGetClassDef(
Ctxt->Server, OptList->ClassId, NULL, 0, NULL,
&Ctxt->UserClass );
ASSERT( NO_ERROR == Error );
if( NO_ERROR != Error ) return Error;
}
if( 0 == OptList->VendorId ) {
Ctxt->VendorClass = NULL;
} else {
Error = MemServerGetClassDef(
Ctxt->Server, OptList->VendorId, NULL, 0, NULL,
&Ctxt->VendorClass );
ASSERT( NO_ERROR == Error );
if( NO_ERROR != Error ) return Error;
}
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &OptList->OptList, DbCreateOptionRoutine );
return Error;
}
DWORD
DbCreateRangeRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_RANGE Range
)
{
return CreateRangeEntry(
Ctxt->Index, Range, Ctxt->Subnet );
}
DWORD
DbCreateExclRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_EXCL Excl
)
{
return CreateExclEntry(
Ctxt->Index, Excl, Ctxt->Subnet );
}
DWORD
DbCreateReservationRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_RESERVATION Reservation
)
{
DWORD Error;
Error = CreateReservationEntry(
Ctxt->Index, Reservation );
if( NO_ERROR != Error ) return Error;
Ctxt->Reservation = Reservation;
//
// Now add the options for this reservation
//
return IterateArrayWithDbCreateRoutine(
Ctxt, &Reservation->Options.Array,
DbCreateOptListRoutine );
}
DWORD
DbCreateScopeRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_SUBNET Subnet
)
{
PM_SSCOPE SScope = NULL;
DWORD Error;
if( Subnet->fSubnet && Subnet->SuperScopeId ) {
DWORD Error;
Error = MemServerFindSScope(
Ctxt->Server, Subnet->SuperScopeId, NULL, &SScope );
if( NO_ERROR != Error ) {
SScope = NULL;
}
}
Error = CreateScopeEntry(
Ctxt->Index, Subnet, SScope );
if( NO_ERROR != Error ) return Error;
//
// Initialize the two fields that will get used later
//
Ctxt->Subnet = Subnet;
Ctxt->Reservation = NULL;
//
// Now add the options for this scope
//
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &Subnet->Options.Array,
DbCreateOptListRoutine );
if( NO_ERROR != Error ) return Error;
//
// Now add the ranges and exclusions
//
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &Subnet->Ranges, DbCreateRangeRoutine );
if( NO_ERROR != Error ) return Error;
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &Subnet->Exclusions, DbCreateExclRoutine );
if( NO_ERROR != Error ) return Error;
//
// Finally, add the reservations
//
return IterateArrayWithDbCreateRoutine(
Ctxt, &Subnet->Reservations,
DbCreateReservationRoutine );
}
DWORD
DbCreateServerRoutine(
IN PDB_CREATE_CONTEXT Ctxt,
IN PM_SERVER Server
)
{
DWORD Error;
Ctxt->Server = Server;
//
// First look through the classes
//
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &Server->ClassDefs.ClassDefArray,
DbCreateClassRoutine );
if( NO_ERROR != Error ) return Error;
//
// Next save the option defs
//
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &Server->OptDefs.Array,
DbCreateOptClassDefRoutine );
if( NO_ERROR != Error ) return Error;
//
// Next save the options
//
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &Server->Options.Array,
DbCreateOptListRoutine );
if( NO_ERROR != Error ) return Error;
//
// Next save the scopes and mcast scopes
//
Error = IterateArrayWithDbCreateRoutine(
Ctxt, &Server->Subnets, DbCreateScopeRoutine );
if( NO_ERROR != Error ) return Error;
return NO_ERROR;
}
DWORD
SaveConfigurationToFile(
IN PM_SERVER Server
)
{
DB_CREATE_CONTEXT Ctxt;
DWORD Error;
ZeroMemory( &Ctxt, sizeof(Ctxt) );
Error = DbCreateServerRoutine(
&Ctxt, Server );
if( NO_ERROR != Error ) {
Tr("DbCreateServerRoutine: %ld\n", Error);
} else {
//
// Sentinel
//
DBCFG_ENTRY Entry;
ZeroMemory( &Entry, sizeof(Entry) );
Entry.Bitmasks = (
Bitmasks[DBCFG_INDEX] | Bitmasks[DBCFG_TYPE] );
Entry.Type = DBCFG_END;
Error = CreateDbEntry( &Entry );
if( NO_ERROR != Error ) {
Tr("Create last entry: %ld\n", Error );
}
}
Tr("SaveConfigurationToFile: %ld\n", Error);
return Error;
}
DWORD
GetColumnFromMemory(
IN OUT LPBYTE *Mem,
IN OUT ULONG *MemSize,
IN ULONG Col,
IN OUT PVOID Buffer,
IN ULONG BufSize,
IN OUT ULONG *CopiedSize
)
{
WORD *WordMem = (WORD *)*Mem;
DWORD Size;
if( *MemSize < sizeof(WORD)*2 ) return ERROR_INVALID_DATA;
if( Col != WordMem[0] ) return JET_wrnColumnNull;
Size = sizeof(WORD)*(
2 + (WordMem[1]+sizeof(WORD)-1)/sizeof(WORD) );
if( Size > *MemSize ) return ERROR_INVALID_DATA;
if( WordMem[1] >= BufSize ) *CopiedSize = BufSize;
else *CopiedSize = WordMem[1];
memcpy(Buffer, &WordMem[2], *CopiedSize );
(*Mem) += Size;
(*MemSize) -= Size;
if( WordMem[1] > BufSize ) return JET_wrnBufferTruncated;
return NO_ERROR;
}
DWORD
ReadDbEntry(
IN OUT LPBYTE *Mem,
IN OUT ULONG *MemSize,
IN PDBCFG_ENTRY Entry,
IN PVOID Buffer,
IN ULONG BufSize
)
{
DWORD Size, CopiedSize, i, OldMemSize, DummySize;
JET_ERR JetError;
LPVOID Data, Ptr;
LPBYTE OldMem;
OldMemSize = *MemSize;
OldMem = *Mem;
ZeroMemory( Entry, sizeof(*Entry) );
ZeroMemory( Buffer, BufSize );
for( i = 0; i < DBCFG_LAST_COLUMN; i ++ ) {
//
// Info should be read at the very end to avoid screwing
// up alignment as info is binary while the rest of the
// variable size columns are all WCHAR strings
//
if( i == DBCFG_INFO ) continue;
Size = EntryMap[i].Size;
Data = EntryMap[i].Offset + (LPBYTE)Entry;
Ptr = Data;
if( 0 == Size ) {
//
// Calculate the size of the string
//
Data = Buffer;
Size = BufSize;
}
JetError = GetColumnFromMemory(
Mem, MemSize, i, Data, Size, &CopiedSize );
//
// If the column doesn't exist, continue
//
if( JET_wrnColumnNull == JetError ) continue;
if( JET_wrnBufferTruncated == JetError &&
Data == Buffer ) {
(*Mem) = OldMem;
(*MemSize) = OldMemSize;
return ERROR_INSUFFICIENT_BUFFER;
}
if( NO_ERROR != JetError ) {
Tr( "GetColumnFromMemory: %ld\n", JetError );
return JetError;
}
//
// If it is any of the variable sized params, then
// set the ptr to point to the buffer where the data is
// copied, and also update the buffer.
//
if( Data == Buffer ) {
(*(LPVOID *)Ptr) = Buffer;
BufSize -= CopiedSize;
Buffer = (PVOID)(((PUCHAR)Buffer) + CopiedSize);
} else {
ASSERT( CopiedSize == Size );
}
//
// Indicate that the column was retrieved successfully
//
Entry->Bitmasks |= Bitmasks[i];
}
//
// Read the info field
//
Size = BufSize;
JetError = GetColumnFromMemory(
Mem, MemSize, DBCFG_INFO, Buffer, Size, &CopiedSize );
GetColumnFromMemory(
Mem, MemSize, DBCFG_LAST_COLUMN+1,NULL, 0, &DummySize);
if( JET_wrnColumnNull == JetError ) return NO_ERROR;
if( JET_wrnBufferTruncated == JetError ) {
(*Mem) = OldMem;
(*MemSize) = OldMemSize;
return ERROR_INSUFFICIENT_BUFFER;
}
if( NO_ERROR != JetError ) {
Tr("GetColumnFromMemory: %ld\n", JetError );
return JetError;
}
Entry->Info = Buffer;
Entry->InfoSize = CopiedSize;
Entry->Bitmasks |= Bitmasks[DBCFG_INFO];
return NO_ERROR;
}
DWORD
ReadDbEntryEx(
IN OUT LPBYTE *Mem,
IN OUT ULONG *MemSize,
IN PDBCFG_ENTRY Entry
)
{
PVOID Buffer;
ULONG BufSize;
DWORD Error;
Buffer = NULL;
BufSize = 512;
do {
if( NULL != Buffer ) LocalFree(Buffer);
BufSize *= 2;
Buffer = LocalAlloc( LPTR, BufSize );
if( NULL == Buffer ) return ERROR_NOT_ENOUGH_MEMORY;
Error = ReadDbEntry(Mem, MemSize, Entry, Buffer, BufSize);
} while( ERROR_INSUFFICIENT_BUFFER == Error );
if( !(Entry->Bitmasks & Bitmasks[DBCFG_INDEX]) ||
!(Entry->Bitmasks & Bitmasks[DBCFG_TYPE]) ) {
if( NO_ERROR == Error ) {
ASSERT( FALSE );
Error = ERROR_INTERNAL_ERROR;
}
}
if( NO_ERROR != Error ) {
LocalFree( Buffer );
return Error;
}
Entry->Buf = Buffer;
return NO_ERROR;
}
DWORD
AddDbEntry(
IN PM_SERVER Server,
IN PDBCFG_ENTRY Entry
)
{
DWORD UserId, VendorId, SScopeId, Error;
PM_SUBNET Subnet;
PM_OPTCLASS OptClass;
PM_OPTION Option, DelOpt;
PM_RANGE DelRange;
PM_EXCL DelExcl;
PM_RESERVATION Reservation;
PM_CLASSDEF ClassDef;
PM_SSCOPE SScope;
Subnet = NULL;
OptClass = NULL;
Option = DelOpt = NULL;
Reservation = NULL;
DelRange = NULL;
DelExcl = NULL;
UserId = 0;
VendorId = 0;
SScopeId = 0;
if( Entry->UserClass ) {
Error = MemServerGetClassDef(
Server, 0, Entry->UserClass, 0, NULL, &ClassDef );
ASSERT( NO_ERROR == Error );
if( NO_ERROR != Error ) return Error;
ASSERT( ClassDef->IsVendor == FALSE );
UserId = ClassDef->ClassId;
}
if( Entry->VendorClass ) {
Error = MemServerGetClassDef(
Server, 0, Entry->VendorClass, 0, NULL, &ClassDef );
ASSERT( NO_ERROR == Error );
if( NO_ERROR != Error ) return Error;
ASSERT( ClassDef->IsVendor == TRUE);
VendorId = ClassDef->ClassId;
}
if( Entry->SuperScope ) {
Error = MemServerFindSScope(
Server, INVALID_SSCOPE_ID, Entry->SuperScope, &SScope );
if( NO_ERROR == Error ) {
SScopeId = SScope->SScopeId;
} else if( ERROR_FILE_NOT_FOUND != Error ) {
return Error;
} else {
Error = MemSScopeInit( &SScope, 0, Entry->SuperScope );
if( NO_ERROR != Error ) return Error;
Error = MemServerAddSScope( Server, SScope );
if( NO_ERROR != Error ) {
MemSScopeCleanup( SScope );
return Error;
}
SScopeId = SScope->SScopeId;
}
}
switch( Entry->Type ) {
case DBCFG_CLASS :
//
// Flags = IsVendor, SubType =Type, Info = ActualBytes
//
return MemServerAddClassDef(
Server, MemNewClassId(), Entry->Flags, Entry->Name,
Entry->Comment, Entry->InfoSize, Entry->Info );
case DBCFG_OPTDEF :
//
// OptionId = OptId, SubType = Type, Info = OptVal
//
return MemServerAddOptDef(
Server, UserId, VendorId, Entry->OptionId,
Entry->Name, Entry->Comment, Entry->SubType,
Entry->Info, Entry->InfoSize );
case DBCFG_OPT:
//
// OptionId = OptId, Info = Val
// If this is a reservation option, address is set to
// reserved client address. If this is a subnet option,
// address is set to subnet address. If this is a mscope
// option, scopeid is set to mscope scopeid. If it is a
// global option, neither address not scopeid is set.
//
if( Entry->Bitmasks & Bitmasks[DBCFG_MSCOPEID] ) {
Error = MemServerFindMScope(
Server, Entry->MscopeId, NULL, &Subnet );
if( NO_ERROR != Error ) return Error;
OptClass = &Subnet->Options;
} else if( 0 == (Entry->Bitmasks & Bitmasks[DBCFG_IPADDRESS] )) {
OptClass = &Server->Options;
} else {
Error = MemServerGetUAddressInfo(
Server, Entry->IpAddress, &Subnet, NULL, NULL,
&Reservation );
ASSERT( NO_ERROR == Error );
if( NO_ERROR != Error ) return Error;
if( NULL != Reservation ) {
OptClass = &Reservation->Options;
} else OptClass = &Subnet->Options;
}
Error = MemOptInit(
&Option, Entry->OptionId, Entry->InfoSize,
Entry->Info );
if( NO_ERROR != Error ) return Error;
Error = MemOptClassAddOption(
OptClass, Option, UserId, VendorId, &DelOpt );
ASSERT( NULL == DelOpt );
if( NO_ERROR != Error ) MemFree( Option );
return Error;
case DBCFG_SCOPE:
//
// IpAddress = Address, Mask = Mask, SubType = State,
// Flags = Policy
//
Error = MemSubnetInit(
&Subnet, Entry->IpAddress, Entry->Mask,
Entry->SubType, SScopeId, Entry->Name, Entry->Comment );
if( NO_ERROR != Error ) return Error;
Error = MemServerAddSubnet( Server, Subnet );
if( NO_ERROR != Error ) MemSubnetCleanup( Subnet );
return Error;
case DBCFG_MSCOPE :
//
// MscopeId = MScopeId, Ttl = TTL, MscopeLang = LangTag,
// ExpiryTime = ExpiryTime, SubType = State, Flags =
// Policy..
//
Error = MemMScopeInit(
&Subnet, Entry->MscopeId, Entry->SubType,
Entry->Flags, (BYTE)Entry->Ttl, Entry->Name,
Entry->Comment, Entry->MscopeLang,
*(DATE_TIME *)&Entry->ExpiryTime );
if( NO_ERROR != Error ) return Error;
Error = MemServerAddMScope( Server, Subnet );
if( NO_ERROR != Error ) MemSubnetCleanup( Subnet );
Subnet->ServerPtr = Server;
return Error;
case DBCFG_RANGE :
//
// RangeStart = Start, RangeEnd = End, RangeMask = Mask,
// Flags = State, BootpAllocated, BootpMax =
// MaxBootpAllowed... Also, IpAddress or MscopeId
//
if( Entry->Bitmasks & Bitmasks[DBCFG_IPADDRESS] ) {
Error = MemServerGetUAddressInfo(
Server, Entry->IpAddress, &Subnet, NULL, NULL,
NULL );
} else {
Error = MemServerFindMScope(
Server, Entry->MscopeId, NULL, &Subnet );
}
if( NO_ERROR != Error ) return Error;
return MemSubnetAddRange(
Subnet, Entry->RangeStart, Entry->RangeEnd,
Entry->Flags, Entry->BootpAllocated, Entry->BootpMax,
&DelRange );
case DBCFG_EXCL:
//
// RangeStart = Start, RangeEnd = End
//
if( Entry->Bitmasks & Bitmasks[DBCFG_IPADDRESS] ) {
Error = MemServerGetUAddressInfo(
Server, Entry->IpAddress, &Subnet, NULL, NULL,
NULL );
} else {
Error = MemServerFindMScope(
Server, Entry->MscopeId, NULL, &Subnet );
}
if( NO_ERROR != Error ) return Error;
return MemSubnetAddExcl(
Subnet, Entry->RangeStart, Entry->RangeEnd, &DelExcl
);
case DBCFG_RESERVATION :
//
// IpAddress = Address, Flags = Flags, Info = ClientUID
//
Error = MemServerGetAddressInfo(
Server, Entry->IpAddress, &Subnet, NULL, NULL, NULL );
if( NO_ERROR != Error ) return Error;
return MemReserveAdd(
&Subnet->Reservations, Entry->IpAddress,
Entry->Flags, Entry->Info, Entry->InfoSize );
default:
return ERROR_INTERNAL_ERROR;
}
}
DWORD
AddDbEntryEx(
IN PM_SERVER Server,
IN PDBCFG_ENTRY Entry
)
{
DWORD Error;
LPSTR EntryTypes[] = {
"Class", "Opt", "OptDef", "Scope", "Mscope", "Range",
"Excl", "Reservation", "Unknown1", "Unknown2", "Unknown3"
};
Error = AddDbEntry( Server, Entry );
if( NO_ERROR != Error ) {
Tr("Error adding entry[%ld] %s: 0x%lx\n",
Entry->Index, EntryTypes[Entry->Type], Error );
}
return Error;
}
DWORD
ReadDbEntries(
IN OUT LPBYTE *Mem,
IN OUT ULONG *MemSize,
IN OUT PM_SERVER *Server
)
{
DBCFG_ENTRY Entry;
DWORD Error = NO_ERROR;
Error = MemServerInit(
Server, -1, 0, 0, NULL, NULL );
if( NO_ERROR != Error ) return Error;
while( Error == NO_ERROR ) {
Error = ReadDbEntryEx( Mem, MemSize, &Entry );
if( NO_ERROR != Error ) {
Tr( "ReadDbEntryEx: %ld\n", Error );
break;
}
if( Entry.Type == DBCFG_END ) {
Error = NO_ERROR;
break;
}
Error = AddDbEntryEx( *Server, &Entry );
if( NULL != Entry.Buf ) LocalFree( Entry.Buf );
if( NO_ERROR != Error ) {
Tr( "AddDbEntryEx: %ld\n", Error );
return Error;
}
}
Tr("ReadDbEntries: %ld\n", Error);
if( NO_ERROR != Error ) {
MemServerFree( *Server );
(*Server) = NULL;
}
return Error;
}