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

2017 lines
50 KiB
C

/*++
Copyright (C) 1999 Microsoft Coporation
Module Name:
db2file.c
Abstract:
This module reads the database records and writes them into a
file format.
--*/
#include <precomp.h>
enum {
RecordTypeDbEntry,
RecordTypeMcastDbEntry,
};
//
// database table and field names.
//
#define IPADDRESS_INDEX 0
#define HARDWARE_ADDRESS_INDEX 1
#define STATE_INDEX 2
#define MACHINE_INFO_INDEX 3
#define MACHINE_NAME_INDEX 4
#define LEASE_TERMINATE_INDEX 5
#define SUBNET_MASK_INDEX 6
#define SERVER_IP_ADDRESS_INDEX 7
#define SERVER_NAME_INDEX 8
#define CLIENT_TYPE_INDEX 9
#define MAX_INDEX 10
#define SAVE_THRESHOLD (1000000L)
//
// Globals
//
DWORD JetVersion;
CHAR DatabaseName[1024], DatabasePath[1024];
HMODULE hJet;
JET_INSTANCE JetInstance;
JET_SESID JetSession;
JET_DBID JetDb;
JET_TABLEID JetTbl;
PUCHAR SaveBuf;
ULONG SaveBufSize;
HANDLE hTextFile, hMapping;
PVOID FileView;
WCHAR Winnt32Path[MAX_PATH*2];
CHAR System32Path[MAX_PATH*2];
JET_ERR (JET_API *pJetSetCurrentIndex)(
JET_SESID sesid,
JET_TABLEID tableid,
const char *szIndexName
);
JET_ERR (JET_API *pJetRetrieveColumn)(
JET_SESID sesid,
JET_TABLEID tableid,
JET_COLUMNID columnid,
void *pvData,
unsigned long cbData,
unsigned long *pcbActual,
JET_GRBIT grbit,
JET_RETINFO *pretinfo );
JET_ERR (JET_API *pJetSetColumn)(
JET_SESID sesid,
JET_TABLEID tableid,
JET_COLUMNID columnid,
const void *pvData,
unsigned long cbData,
JET_GRBIT grbit,
JET_SETINFO *psetinfo );
JET_ERR (JET_API *pJetMove)(
JET_SESID sesid,
JET_TABLEID tableid,
long cRow,
JET_GRBIT grbit );
JET_ERR (JET_API *pJetSetSystemParameter)(
JET_INSTANCE *pinstance,
JET_SESID sesid,
unsigned long paramid,
ULONG_PTR lParam,
const char *sz );
JET_ERR (JET_API *pJetBeginTransaction)(
JET_SESID sesid
);
JET_ERR (JET_API *pJetPrepareUpdate)(
JET_SESID sesid,
JET_TABLEID tableid,
unsigned long prep );
JET_ERR (JET_API *pJetUpdate)(
JET_SESID sesid,
JET_TABLEID tableid,
void *pvBookmark,
unsigned long cbBookmark,
unsigned long *pcbActual);
JET_ERR (JET_API *pJetCommitTransaction)( JET_SESID sesid, JET_GRBIT grbit );
JET_ERR (JET_API *pJetRollback)( JET_SESID sesid, JET_GRBIT grbit );
JET_ERR (JET_API *pJetTerm)( JET_INSTANCE instance );
JET_ERR (JET_API *pJetTerm2)( JET_INSTANCE instance, JET_GRBIT grbit );
JET_ERR (JET_API *pJetEndSession)( JET_SESID sesid, JET_GRBIT grbit );
JET_ERR (JET_API *pJetBeginSession)(
JET_INSTANCE instance,
JET_SESID *psesid,
const char *szUserName,
const char *szPassword );
JET_ERR (JET_API *pJetInit)( JET_INSTANCE *pinstance);
JET_ERR (JET_API *pJetDetachDatabase)(
JET_SESID sesid,
const char *szFilename );
JET_ERR (JET_API *pJetAttachDatabase)(
JET_SESID sesid,
const char *szFilename,
JET_GRBIT grbit );
JET_ERR (JET_API *pJetOpenDatabase)(
JET_SESID sesid,
const char *szFilename,
const char *szConnect,
JET_DBID *pdbid,
JET_GRBIT grbit );
JET_ERR (JET_API *pJetCloseDatabase)(
JET_SESID sesid,
JET_DBID dbid,
JET_GRBIT grbit );
JET_ERR (JET_API *pJetOpenTable)(
JET_SESID sesid,
JET_DBID dbid,
const char *szTableName,
const void *pvParameters,
unsigned long cbParameters,
JET_GRBIT grbit,
JET_TABLEID *ptableid );
JET_ERR (JET_API *pJetCloseTable)( JET_SESID sesid, JET_TABLEID tableid );
JET_ERR (JET_API *pJetGetTableColumnInfo)(
JET_SESID sesid,
JET_TABLEID tableid,
const char *szColumnName,
void *pvResult,
unsigned long cbMax,
unsigned long InfoLevel );
JET_ERR (JET_API *pJetGetIndexInfo)(
JET_SESID sesid,
JET_DBID dbid,
const char *szTableName,
const char *szIndexName,
void *pvResult,
unsigned long cbResult,
unsigned long InfoLevel );
#define DB_FUNC(F,I,S) \
{#F, TEXT(#F), #F "@" #S, I, (FARPROC *)& p ## F }
typedef struct _DB_FUNC_ENTRY {
LPSTR FuncName;
LPWSTR FuncNameW;
LPSTR AltName;
DWORD Index;
FARPROC *FuncPtr;
} DB_FUNC_ENTRY;
DB_FUNC_ENTRY FuncTable[] = {
DB_FUNC(JetSetCurrentIndex, 164, 12),
DB_FUNC(JetRetrieveColumn, 157, 32),
DB_FUNC(JetSetColumn, 162, 28),
DB_FUNC(JetMove, 147, 16),
DB_FUNC(JetSetSystemParameter, 165, 20),
DB_FUNC(JetTerm, 167, 4),
DB_FUNC(JetTerm2, 0, 8),
DB_FUNC(JetEndSession, 124, 8),
DB_FUNC(JetBeginSession, 104, 16),
DB_FUNC(JetInit, 145, 4),
DB_FUNC(JetDetachDatabase, 121, 8),
DB_FUNC(JetAttachDatabase, 102, 12),
DB_FUNC(JetOpenDatabase, 148, 20),
DB_FUNC(JetOpenTable, 149, 28),
DB_FUNC(JetGetTableColumnInfo, 137, 24),
DB_FUNC(JetCloseTable,108, 8),
DB_FUNC(JetCloseDatabase, 107, 12),
DB_FUNC(JetGetIndexInfo, 131, 28),
DB_FUNC(JetBeginTransaction, 105, 4),
DB_FUNC(JetPrepareUpdate, 151, 12),
DB_FUNC(JetUpdate, 168, 20),
DB_FUNC(JetCommitTransaction, 109, 8),
DB_FUNC(JetRollback, 160, 8),
};
#define JetSetCurrentIndex pJetSetCurrentIndex
#define JetRetrieveColumn pJetRetrieveColumn
#define JetSetColumn pJetSetColumn
#define JetMove pJetMove
#define JetSetSystemParameter pJetSetSystemParameter
#define JetTerm pJetTerm
#define JetTerm2 pJetTerm2
#define JetEndSession pJetEndSession
#define JetBeginSession pJetBeginSession
#define JetInit pJetInit
#define JetDetachDatabase pJetDetachDatabase
#define JetAttachDatabase pJetAttachDatabase
#define JetOpenDatabase pJetOpenDatabase
#define JetOpenTable pJetOpenTable
#define JetGetTableColumnInfo pJetGetTableColumnInfo
#define JetCloseTable pJetCloseTable
#define JetCloseDatabase pJetCloseDatabase
#define JetGetIndexInfo pJetGetIndexInfo
#define JetBeginTransaction pJetBeginTransaction
#define JetPrepareUpdate pJetPrepareUpdate
#define JetUpdate pJetUpdate
#define JetCommitTransaction pJetCommitTransaction
#define JetRollback pJetRollback
typedef struct _TABLE_INFO {
CHAR *ColName;
JET_COLUMNID ColHandle;
BOOL fPresent;
JET_COLTYP ColType;
} TABLE_INFO, *LPTABLE_INFO;
#define IPADDRESS_STRING "IpAddress"
#define HARDWARE_ADDRESS_STRING "HardwareAddress"
#define STATE_STRING "State"
#define MACHINE_INFO_STRING "MachineInformation"
#define MACHINE_NAME_STRING "MachineName"
#define LEASE_TERMINATE_STRING "LeaseTerminates"
#define SUBNET_MASK_STRING "SubnetMask"
#define SERVER_IP_ADDRESS_STRING "ServerIpAddress"
#define SERVER_NAME_STRING "ServerName"
#define CLIENT_TYPE "ClientType"
static TABLE_INFO ClientTable[] = {
{ IPADDRESS_STRING , 0, 1, JET_coltypLong },
{ HARDWARE_ADDRESS_STRING , 0, 1, JET_coltypBinary },
{ STATE_STRING , 0, 1, JET_coltypUnsignedByte },
{ MACHINE_INFO_STRING , 0, 1, JET_coltypBinary }, // must modify MACHINE_INFO_SIZE if this changes
{ MACHINE_NAME_STRING , 0, 1, JET_coltypBinary },
{ LEASE_TERMINATE_STRING , 0, 1, JET_coltypCurrency },
{ SUBNET_MASK_STRING , 0, 1, JET_coltypLong },
{ SERVER_IP_ADDRESS_STRING, 0, 1, JET_coltypLong },
{ SERVER_NAME_STRING , 0, 1, JET_coltypBinary },
{ CLIENT_TYPE , 0, 1, JET_coltypUnsignedByte }
};
#define MAGIC_COOKIE_NT4 'NT4 '
#define MAGIC_COOKIE_NT5 'W2K '
#define MAGIC_COOKIE_NT5_PLUS 'W2K1'
DWORD
GetCurrentMagicCookie(
VOID
)
{
OSVERSIONINFO Ver;
Ver.dwOSVersionInfoSize = sizeof(Ver);
if( FALSE == GetVersionEx(&Ver) ) return MAGIC_COOKIE_NT5_PLUS;
if( Ver.dwMajorVersion == 4 ) return MAGIC_COOKIE_NT4;
else if( Ver.dwMajorVersion == 5 ) {
if( Ver.dwBuildNumber >= 2200 ) return MAGIC_COOKIE_NT5_PLUS;
else return MAGIC_COOKIE_NT5;
}
return MAGIC_COOKIE_NT4;
}
DWORD
OpenTextFile(
IN LPWSTR FileName,
IN BOOL fRead,
OUT HANDLE *hFile,
OUT LPBYTE *Mem,
OUT ULONG *MemSize
)
{
DWORD Error, Flags, LoSize, HiSize;
Flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN;
hTextFile = CreateFileW(
FileName, GENERIC_READ | GENERIC_WRITE | DELETE,
FILE_SHARE_READ, NULL,
fRead ? OPEN_EXISTING : CREATE_ALWAYS,
Flags, NULL );
if( hTextFile == INVALID_HANDLE_VALUE ) {
hTextFile = NULL;
Error = GetLastError();
if( !fRead || ERROR_FILE_NOT_FOUND != Error ) {
Tr("CreateFile<%ws>: %ld\n", FileName, Error );
}
return Error;
}
(*hFile) = hTextFile;
if( !fRead ) {
//
// Write the magic cookie
//
Flags = GetCurrentMagicCookie();
if( FALSE == WriteFile(
hTextFile, (LPBYTE)&Flags, sizeof(Flags), &LoSize,
NULL ) ) {
Error = GetLastError();
CloseHandle(hTextFile);
return Error;
}
return NO_ERROR;
}
LoSize = GetFileSize( hTextFile, &HiSize );
if( -1 == LoSize && NO_ERROR != GetLastError() ) {
return GetLastError();
}
if( LoSize <= sizeof(DWORD) ) {
CloseHandle(hTextFile);
return ERROR_INVALID_DATA;
}
(*MemSize) = LoSize;
(*Mem) = NULL;
hMapping = CreateFileMapping(
hTextFile, NULL, PAGE_READONLY | SEC_COMMIT, HiSize, LoSize,
NULL );
if( NULL == hMapping ) {
Error = GetLastError();
Tr("Can't map file: %ld\n", Error );
return Error;
}
FileView = MapViewOfFile(
hMapping, FILE_MAP_READ, 0, 0, 0 );
if( NULL == FileView ) {
Error = GetLastError();
Tr("Can't create view: %ld\n", Error );
CloseHandle( hMapping );
CloseHandle( hTextFile );
hTextFile = NULL;
hMapping = NULL;
return Error;
}
(*Mem) = FileView;
//
// Before okaying, check if the version of the file is
// greater than current version
//
Error = NO_ERROR;
CopyMemory(&Flags, *Mem, sizeof(Flags));
switch(GetCurrentMagicCookie()) {
case MAGIC_COOKIE_NT5_PLUS :
if( Flags != MAGIC_COOKIE_NT5 &&
Flags != MAGIC_COOKIE_NT5_PLUS &&
Flags != MAGIC_COOKIE_NT4 ) {
Error = ERROR_NOT_SUPPORTED;
}
break;
case MAGIC_COOKIE_NT5 :
if( Flags != MAGIC_COOKIE_NT5 &&
Flags != MAGIC_COOKIE_NT4 ) {
Error = ERROR_NOT_SUPPORTED;
}
break;
case MAGIC_COOKIE_NT4 :
if( Flags != MAGIC_COOKIE_NT4 ) {
Error = ERROR_NOT_SUPPORTED;
}
break;
}
if( NO_ERROR != Error ) {
UnmapViewOfFile(FileView);
CloseHandle( hMapping );
CloseHandle( hTextFile );
hTextFile = NULL;
hMapping = NULL;
FileView = NULL;
return Error;
}
*MemSize -= sizeof(DWORD);
(*Mem) += sizeof(DWORD);
return NO_ERROR;
}
VOID
CloseTextFile(
IN OUT HANDLE hFile,
IN OUT LPBYTE Mem
)
{
ASSERT( hFile == hTextFile );
if( NULL != FileView ) UnmapViewOfFile( FileView );
FileView = NULL;
if( NULL != hMapping ) CloseHandle( hMapping );
hMapping = NULL;
if( NULL != hTextFile ) CloseHandle( hTextFile );
hTextFile = NULL;
}
ULONG
ByteSwap(
IN ULONG Source
)
{
ULONG swapped;
swapped = ((Source) << (8 * 3)) |
((Source & 0x0000FF00) << (8 * 1)) |
((Source & 0x00FF0000) >> (8 * 1)) |
((Source) >> (8 * 3));
return swapped;
}
LPSTR
IpAddressToString(
IN ULONG Address
)
{
static CHAR Buffer[30];
PUCHAR pAddress;
pAddress = (PUCHAR)&Address;
sprintf(Buffer, "%d.%d.%d.%d", pAddress[0], pAddress[1],
pAddress[2], pAddress[3] );
return Buffer;
}
VOID static
CleanupDatabase(
VOID
)
{
if( JetTbl != 0 ) {
JetCloseTable( JetSession, JetTbl );
JetTbl = 0;
}
if( JetSession != 0 ) {
JetEndSession( JetSession, 0 );
JetSession = 0;
}
if( NULL != hJet ) {
if( NULL != JetTerm2 ) {
JetTerm2( JetInstance, JET_bitTermComplete );
} else {
JetTerm( JetInstance );
}
FreeLibrary( hJet ); hJet = NULL;
}
JetInstance = 0;
}
DWORD
LoadAndLinkRoutines(
IN DWORD JetVersion
)
{
DWORD Error, i;
LPTSTR Module;
LPSTR FuncName;
Module = NULL;
switch( JetVersion ) {
case LoadJet2001 : Module = TEXT("esent.dll"); break;
case LoadJet97 : Module = TEXT("esent.dll"); break;
case LoadJet500 : Module = TEXT("jet500.dll"); break;
case LoadJet200 : Module = TEXT("jet.dll"); break;
default: Module = TEXT("esent.dll"); break;
}
hJet = LoadLibrary( Module );
if( NULL == hJet ) {
Error = GetLastError();
} else {
Error = NO_ERROR;
}
Tr( "Loading %ws: %ld\n", Module, Error );
if( NO_ERROR != Error ) return Error;
for( i = 0; i < sizeof(FuncTable)/sizeof(FuncTable[0]); i ++ ) {
(*FuncTable[i].FuncPtr) = NULL;
}
for( i = 0; i < sizeof(FuncTable)/sizeof(FuncTable[0]); i ++ ) {
if( LoadJet200 != JetVersion ) {
FuncName = FuncTable[i].FuncName;
} else {
if( 0 == FuncTable[i].Index ) {
(*FuncTable[i].FuncPtr) = NULL;
continue;
}
FuncName = (LPSTR)ULongToPtr(FuncTable[i].Index);
}
Error = NO_ERROR;
(*FuncTable[i].FuncPtr) = GetProcAddress(hJet, FuncName);
if( NULL == FuncTable[i].FuncPtr ) {
Error = GetLastError();
if( LoadJet97 == JetVersion || LoadJet2001 == JetVersion ) {
(*FuncTable[i].FuncPtr) = GetProcAddress(
hJet, FuncTable[i].AltName );
if( NULL != FuncTable[i].FuncPtr ) continue;
Error = GetLastError();
}
}
Tr("GetProcAddr[%ws]: %ld\n", FuncTable[i].FuncNameW, Error );
if( NO_ERROR != Error ) break;
}
//
// if erred out, cleanup
//
if( NO_ERROR != Error ) {
FreeLibrary( hJet );
hJet = NULL;
}
return Error;
}
DWORD
SetJetParams(
IN DWORD JetVersion,
IN LPSTR DbName,
IN LPSTR DbPath
)
{
DWORD Error, JetParam, LogFileSize;
CHAR Temp[2048];
LPSTR DbSysFile = "\\system.mdb";
LPSTR DbBaseName = "j50";
JetInstance = 0;
LogFileSize = 1000;
if( JetVersion == LoadJet2001 ) LogFileSize = 1024;
strcpy(Temp, DbPath);
if( LoadJet200 == JetVersion ) {
strcat(Temp, DbSysFile);
JetParam = JET_paramSysDbPath_OLD;
} else {
strcat(Temp, "\\");
if( LoadJet97 > JetVersion ) {
JetParam = JET_paramSystemPath_OLD;
} else {
JetParam = JET_paramSystemPath;
}
}
Error = JetSetSystemParameter(
&JetInstance, (JET_SESID)0, JetParam, 0, Temp );
Tr("SetDbParam %ld: %ld\n", JetParam, Error );
if( NO_ERROR != Error ) return Error;
if( LoadJet200 != JetVersion ) {
if( LoadJet97 > JetVersion ) {
JetParam = JET_paramBaseName_OLD;
} else {
JetParam = JET_paramBaseName;
}
Error = JetSetSystemParameter(
&JetInstance, (JET_SESID)0, JetParam, 0, DbBaseName );
Tr("SetDbParam %ld: %ld\n", JetParam, Error );
if( NO_ERROR != Error ) return Error;
}
if( LoadJet200 != JetVersion ) {
if( LoadJet97 <= JetVersion ) {
JetParam = JET_paramLogFileSize;
} else {
JetParam = JET_paramLogFileSize_OLD;
}
Error = JetSetSystemParameter(
&JetInstance, (JET_SESID)0, JetParam, LogFileSize, NULL );
Tr("SetDbParam %ld: %ld\n", JetParam, Error );
if( NO_ERROR != Error ) return Error;
}
if( LoadJet200 != JetVersion ) {
Error = JetSetSystemParameter(
&JetInstance, (JET_SESID)0,
JET_paramCheckFormatWhenOpenFail, 1, NULL );
JetParam = JET_paramCheckFormatWhenOpenFail;
Tr("SetDbParam %ld: %ld\n", JetParam, Error );
if( NO_ERROR != Error ) return Error;
}
if( LoadJet200 != JetVersion ) {
if( LoadJet97 > JetVersion ) {
JetParam = JET_paramRecovery_OLD;
} else {
JetParam = JET_paramRecovery;
}
Error = JetSetSystemParameter(
&JetInstance, (JET_SESID)0, JetParam, 0, "on");
Tr("SetDbParam %ld: %ld\n", JetParam, Error );
if( NO_ERROR != Error ) return Error;
}
//
// Note: Ideally, the log files should never exist. Even
// if the database is opened in readonly mode, they seem to
// exist. Not sure what else can be done
//
if( LoadJet97 <= JetVersion ) {
JetParam = JET_paramLogFilePath;
} else {
JetParam = JET_paramLogFilePath_OLD;
}
strcpy(Temp, DbPath); strcat( Temp, "\\");
Error = JetSetSystemParameter(
&JetInstance, (JET_SESID)0, JetParam, 0, Temp );
Tr("SetDbParam %ld: %ld\n", JetParam, Error );
return Error;
}
DWORD
OpenDatabase(
IN DWORD JetVersion,
IN LPSTR DbName,
IN LPSTR DbPath
)
{
LONG Error;
DWORD i;
CHAR FilePath[2048];
JET_INDEXLIST TmpIdxList;
JetSession = 0;
JetDb = 0;
JetTbl = 0;
Error = JetInit( &JetInstance );
Tr("JetInit: %ld\n", Error );
if( NO_ERROR != Error ) return Error;
Error = JetBeginSession(
JetInstance, &JetSession, "admin", "" );
Tr("JetBeginSession: %ld\n", Error);
if( Error < 0 ) return Error;
strcpy(FilePath, DbPath );
strcat(FilePath, "\\" );
//
// fix prefast bug 292432
//
if ( strlen( DbName ) < ( 2048 - strlen( FilePath ) ) )
strcat(FilePath, DbName );
Error = JetDetachDatabase( JetSession, NULL );
Tr("JetDetachDatabase:%ld\n", Error );
if( Error < 0 ) return Error;
Error = JetAttachDatabase( JetSession, FilePath, JET_bitDbRecoveryOff );
Tr("JetAttachDatabase:%ld\n", Error );
if( Error < 0 ) return Error;
Error = JetOpenDatabase(
JetSession, FilePath, NULL, &JetDb,
JET_bitDbSingleExclusive );
Tr("JetOpenDatabase: %ld\n", Error);
if( Error < 0 ) return Error;
Error = JetOpenTable(
JetSession, JetDb, (LPSTR)"ClientTable",
NULL, 0, 0,&JetTbl );
Tr("JetOpenTable: %ld\n", Error );
if( Error < 0 ) return Error;
for( i = 0; i < sizeof(ClientTable)/sizeof(ClientTable[0]); i ++ ) {
JET_COLUMNDEF ColDef;
Error = JetGetTableColumnInfo(
JetSession, JetTbl, ClientTable[i].ColName, &ColDef,
sizeof(ColDef), 0 );
if(Error && JET_errColumnNotFound != Error ) {
Tr("JetGetCol: %ld\n", Error );
}
if( Error < 0 ) {
if( JET_errColumnNotFound == Error ) {
ClientTable[i].fPresent = FALSE;
continue;
} else {
return Error;
}
}
if( ColDef.coltyp != ClientTable[i].ColType ) {
ASSERT( FALSE );
Error = ERROR_BAD_FORMAT;
return Error;
}
ClientTable[i].ColHandle = ColDef.columnid;
}
return NO_ERROR;
}
DWORD
LoadAndInitializeDatabase(
IN DWORD JetVersion,
IN LPSTR DbName,
IN LPSTR DbPath
)
{
DWORD Error;
//
// Attempt to load DLL and retrieve function pointers
//
Tr("Loading %ld jet version\n", JetVersion );
Error = LoadAndLinkRoutines( JetVersion );
if( NO_ERROR != Error ) return Error;
//
// set standard jet params
//
Error = SetJetParams( JetVersion, DbName, DbPath );
if( NO_ERROR != Error ) {
FreeLibrary( hJet ); hJet = NULL;
return Error;
}
//
// Attempt to open database
//
Error = OpenDatabase( JetVersion, DbName, DbPath );
if( NO_ERROR != Error ) {
CleanupDatabase();
return Error;
}
return NO_ERROR;
}
DWORD
LoadAndLinkSecurityRoutines(
OUT FARPROC *pGetInfo,
OUT FARPROC *pSetInfo
)
{
HMODULE hAdvapi32;
hAdvapi32 = GetModuleHandle(TEXT("ADVAPI32.DLL"));
if( NULL == hAdvapi32 ) return GetLastError();
(*pGetInfo) = GetProcAddress(hAdvapi32, "GetNamedSecurityInfoA");
if( NULL == *pGetInfo ) return GetLastError();
(*pSetInfo) = GetProcAddress(hAdvapi32, "SetNamedSecurityInfoA");
if( NULL == *pSetInfo ) return GetLastError();
return NO_ERROR;
}
DWORD
ConvertPermissionsOnDbFiles(
VOID
)
{
DWORD Error, dwVersion = GetVersion();
PSECURITY_DESCRIPTOR pSec;
PACL pAcl;
HANDLE hSearch = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAA FileData;
CHAR FileName[1024];
FARPROC pGetInfo, pSetInfo;
CHAR DriversDirPath[MAX_PATH *2 +1];
DWORD PathLen = sizeof(DriversDirPath)-1;
//
// Check if version is atleast NT5.
//
dwVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
if( dwVersion < 5 ) return NO_ERROR;
//
// First get the requried function pointers..
//
Error = LoadAndLinkSecurityRoutines(
&pGetInfo, &pSetInfo );
if( NO_ERROR != Error ) return Error;
ZeroMemory(DriversDirPath, PathLen+1);
PathLen = ExpandEnvironmentStringsA(
"%SystemRoot%\\system32\\drivers", DriversDirPath, PathLen );
if( PathLen == 0 ) {
Error = GetLastError();
return Error;
}
pSec = NULL;
pAcl = NULL;
Error = (DWORD)pGetInfo(
DriversDirPath, //"MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer",
SE_FILE_OBJECT, // SE_REGISTRY_KEY
DACL_SECURITY_INFORMATION, NULL, NULL,
&pAcl, NULL, &pSec );
if( NO_ERROR != Error ) return Error;
Error = (DWORD)pSetInfo(
DatabasePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, pAcl, NULL );
if( NO_ERROR != Error ) return Error;
strcpy(FileName, DatabasePath);
if( FileName[strlen(FileName)-1] != '\\' ) {
strcat(FileName, "\\");
}
strcat(FileName, DatabaseName);
Error = (DWORD)pSetInfo(
FileName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, pAcl, NULL );
if( NO_ERROR != Error ) goto Cleanup;
//
// Now for all files matching "*.log", repeat above operation
//
strcpy(FileName, DatabasePath);
if( FileName[strlen(FileName)-1] != '\\' ) {
strcat(FileName, "\\");
}
strcat(FileName, "*.*");
hSearch = FindFirstFileA( FileName, &FileData );
if( INVALID_HANDLE_VALUE == hSearch ) {
Error = GetLastError();
goto Cleanup;
}
do {
if( 0 != strcmp(FileData.cFileName, ".") &&
0 != strcmp(FileData.cFileName, "..") ) {
strcpy(FileName, DatabasePath);
if( FileName[strlen(FileName)-1] != '\\' ) {
strcat(FileName, "\\");
}
strcat(FileName, FileData.cFileName);
Error = (DWORD)pSetInfo(
FileName, SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION, NULL, NULL, pAcl, NULL );
if( NO_ERROR != Error ) break;
}
Error = FindNextFileA( hSearch, &FileData );
if( FALSE != Error ) Error = NO_ERROR;
else Error = GetLastError();
} while( NO_ERROR == Error );
FindClose( hSearch );
Cleanup:
LocalFree( pSec );
if( ERROR_FILE_NOT_FOUND == Error ) return NO_ERROR;
if( ERROR_NO_MORE_FILES == Error ) return NO_ERROR;
return Error;
}
DWORD
ReadString(
IN HKEY hKey,
IN LPSTR KeyName,
IN LPSTR Buffer,
IN ULONG BufSize
)
{
DWORD Error, Size, Type;
CHAR Str[1024];
Size = sizeof(Str);
Error = RegQueryValueExA(
hKey, KeyName, NULL, &Type, (LPSTR)Str, &Size );
if( NO_ERROR == Error ) {
if( 0 == Size || 1 == Size ) Error = ERROR_NOT_FOUND;
if( Type != REG_SZ && Type != REG_EXPAND_SZ && Type !=
REG_MULTI_SZ ) Error = ERROR_BAD_FORMAT;
}
if( NO_ERROR != Error ) return Error;
Size = ExpandEnvironmentStringsA( (LPSTR)Str, Buffer, BufSize );
if( Size == 0 || Size > BufSize ) {
Error = ERROR_META_EXPANSION_TOO_LONG;
}
Tr("Expansion failed for %s\n", KeyName );
return Error;
}
DWORD
ReadRegistry(
VOID
)
{
HKEY hKey;
DWORD Error, Size, Use351Db, DbType;
CHAR Str[1024];
//
// Open dhcp server parameters key
//
Error = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Parameters"),
0, KEY_READ, &hKey );
Tr("Open Params key failed %ld\n", Error );
if( NO_ERROR != Error ) return Error;
//
// Read database details
//
do {
Error = ReadString(
hKey, "DatabasePath", (LPSTR)DatabasePath,
sizeof(DatabasePath) );
if( NO_ERROR != Error ) {
Tr(" Read DatabasePath failed: %ld\n", Error );
break;
}
Error = ReadString(
hKey, "DatabaseName", (LPSTR)DatabaseName,
sizeof(DatabaseName) );
if( NO_ERROR != Error ) {
Tr("Read DatabaseName failed %ld\n", Error );
break;
}
strcpy(DhcpEximOemDatabaseName, DatabaseName);
strcpy(DhcpEximOemDatabasePath, DatabasePath);
CharToOemA(DhcpEximOemDatabaseName, DhcpEximOemDatabaseName);
CharToOemA(DhcpEximOemDatabasePath, DhcpEximOemDatabasePath);
if( !IsNT5() && !IsNT4() ) JetVersion = LoadJet2001;
else {
if( IsNT5() ) JetVersion = LoadJet97;
else JetVersion = LoadJet500;
Size = sizeof(DWORD);
Error = RegQueryValueExA(
hKey, "Use351Db", NULL, NULL, (LPBYTE)&Use351Db, &Size );
if( NO_ERROR == Error ) {
JetVersion = LoadJet200;
} else {
Size = sizeof(DWORD);
Error = RegQueryValueExA(
hKey, "DbType", NULL, NULL, (LPBYTE)&DbType, &Size );
if( NO_ERROR == Error ) {
switch(DbType) {
case 3: JetVersion = LoadJet200; break;
case 4: JetVersion = LoadJet500; break;
}
}
}
}
Error = NO_ERROR;
} while( 0 );
#if DBG
DbgPrint("JetVersion: %ld\n", JetVersion);
#endif
RegCloseKey( hKey );
return Error;
}
DWORD
InitializeDatabase(
VOID
)
{
DWORD Error;
if( FALSE == SetCurrentDirectoryA(DatabasePath) ) {
Error = GetLastError();
if( ERROR_FILE_NOT_FOUND == Error ||
ERROR_PATH_NOT_FOUND == Error ) {
return ERROR_SERVICE_DOES_NOT_EXIST;
}
return Error;
}
Error = LoadAndInitializeDatabase(
JetVersion, (LPSTR)DatabaseName, (LPSTR)DatabasePath );
if( NO_ERROR != Error ) {
Tr("LoadAndInitializeDatabase(%ld):%ld\n", JetVersion, Error );
}
return Error;
}
JET_ERR
GetColumnValue(
IN DWORD Index,
IN LPSTR Buffer,
IN OUT ULONG *BufSize
)
{
JET_ERR Error = NO_ERROR;
DWORD Size;
if( ClientTable[Index].fPresent == FALSE ) {
(*BufSize) = 0;
return NO_ERROR;
}
Error = JetRetrieveColumn(
JetSession, JetTbl, ClientTable[Index].ColHandle, Buffer,
*BufSize, &Size, 0, NULL );
if( JET_errColumnNotFound == Error ) {
Error = NO_ERROR;
Size = 0;
}
Tr("JetRetrieveColumn(%ld): %ld\n", Index, Error );
if( Error < 0 ) return Error;
(*BufSize) = Size;
return NO_ERROR;
}
JET_ERR
SetColumnValue(
IN DWORD Index,
IN LPSTR Buffer,
IN ULONG BufSize
)
{
JET_ERR Error = NO_ERROR;
if( ClientTable[Index].fPresent == FALSE ) {
return ERROR_CAN_NOT_COMPLETE;
}
Error = JetSetColumn(
JetSession, JetTbl, ClientTable[Index].ColHandle, Buffer,
BufSize, 0, NULL );
Tr("JetSetColumn(%ld): %ld\n", Index, Error );
if( Error < 0 ) return Error;
return NO_ERROR;
}
#define CLIENT_TYPE_UNSPECIFIED 0x0 // for backward compatibility
#define CLIENT_TYPE_DHCP 0x1
#define CLIENT_TYPE_BOOTP 0x2
#define CLIENT_TYPE_BOTH ( CLIENT_TYPE_DHCP | CLIENT_TYPE_BOOTP )
#define ADDRESS_STATE_OFFERED 0
#define ADDRESS_STATE_ACTIVE 1
#define ADDRESS_STATE_DECLINED 2
#define ADDRESS_STATE_DOOM 3
#define ADDRESS_BIT_DELETED 0x80
#define ADDRESS_BIT_UNREGISTERED 0x40
#define ADDRESS_BIT_BOTH_REC 0x20
#define ADDRESS_BIT_CLEANUP 0x10
#define ADDRESS_BITS_MASK 0xF0
DWORD
AddRecord(
IN LPSTR Buffer,
IN ULONG BufSize
);
DWORD
AddScannedClient(
IN DWORD IpAddressNetOrder,
IN DWORD SubnetMaskNetOrder,
IN LPBYTE HwAddr,
IN ULONG HwLen,
IN LPWSTR MachineName,
IN LPWSTR MachineInfo,
IN ULONGLONG ExpirationFileTime,
IN BYTE State,
IN BYTE ClientType
)
{
DWORD i;
CHAR Buffer[1024];
ULONG Length, Size;
Length = 0;
Buffer[Length++] = (BYTE)RecordTypeDbEntry;
CopyMemory(
&Buffer[Length], (PVOID)&IpAddressNetOrder, sizeof(DWORD) );
Length += sizeof(DWORD);
CopyMemory(
&Buffer[Length], (PVOID)&SubnetMaskNetOrder, sizeof(DWORD) );
Length += sizeof(DWORD);
Buffer[Length++] = (BYTE)HwLen;
CopyMemory(&Buffer[Length], HwAddr, HwLen );
Length += HwLen;
if( NULL == MachineName || 0 == *MachineName ) Size = 0;
else Size = sizeof(WCHAR)*(1+wcslen(MachineName));
CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
Length += sizeof(DWORD);
CopyMemory(&Buffer[Length], (PVOID)MachineName, Size );
Length += Size;
if( NULL == MachineInfo || 0 == *MachineInfo ) Size = 0;
else Size = sizeof(WCHAR)*(1+wcslen(MachineInfo));
CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
Length += sizeof(DWORD);
CopyMemory(&Buffer[Length], (PVOID)MachineInfo, Size );
Length += Size;
CopyMemory(&Buffer[Length], (PVOID)&ExpirationFileTime, sizeof(ULONGLONG));
Length += sizeof(ULONGLONG);
Buffer[Length++] = State;
Buffer[Length++] = ClientType;
return AddRecord( Buffer, Length );
}
BOOL
SubnetNotSelected(
IN ULONG Subnet,
IN PULONG Subnets,
IN ULONG nSubnets
)
{
if( nSubnets == 0 ) return FALSE;
while( nSubnets -- ) {
if( Subnet == *Subnets++ ) return FALSE;
}
return TRUE;
}
DWORD static
ScanDatabase(
IN PULONG Subnets,
IN ULONG nSubnets
)
{
LONG Error;
DWORD Count;
Error = JetSetCurrentIndex(
JetSession, JetTbl, NULL );
Tr("JetSetCurrentIndex: %ld\n", Error );
if( Error < 0 ) return Error;
Error = JetMove( JetSession, JetTbl, JET_MoveFirst, 0 );
for( Count = 0 ; Error >= 0 ; Count ++,
Error = JetMove(JetSession, JetTbl, JET_MoveNext, 0) ) {
DWORD IpAddress, SubnetMask, Size, HwLen;
FILETIME Expiration;
CHAR HwAddress[256];
WCHAR MachineName[300], MachineInfo[300];
BYTE Type, State;
//
// Get current client's info.
//
Size = sizeof(IpAddress);
Error = GetColumnValue(
IPADDRESS_INDEX, (PVOID)&IpAddress, &Size );
if( NO_ERROR != Error ) break;
if( Size != sizeof(IpAddress) ) {
Tr("Invalid Ip size\n");
continue;
}
Size = sizeof(SubnetMask);
Error = GetColumnValue(
SUBNET_MASK_INDEX, (PVOID)&SubnetMask, &Size );
if( NO_ERROR != Error ) break;
if( Size != sizeof(SubnetMask) ) {
Tr("Invalid mask size\n");
continue;
}
//
// Check if the subnet specified matches the specific
// subnet
//
if( SubnetNotSelected(
IpAddress&SubnetMask, Subnets, nSubnets ) ) {
continue;
}
HwLen = sizeof(HwAddress);
Error = GetColumnValue(
HARDWARE_ADDRESS_INDEX, (PVOID)HwAddress, &HwLen );
if( NO_ERROR != Error ) break;
Size = sizeof(MachineName);
Error = GetColumnValue(
MACHINE_NAME_INDEX, (PVOID)MachineName, &Size );
if( NO_ERROR != Error ) break;
if( (Size % 2) != 0 ) {
Tr("Invalid name size\n");
continue;
}
MachineName[Size/2] = L'\0';
Size = sizeof(MachineInfo);
Error = GetColumnValue(
MACHINE_INFO_INDEX, (PVOID)MachineInfo, &Size );
if( NO_ERROR != Error ) break;
if( (Size % 2) != 0 ) {
Tr("Invalid Info size\n");
continue;
}
MachineInfo[Size/2] = L'\0';
Size = sizeof(Expiration);
Error = GetColumnValue(
LEASE_TERMINATE_INDEX, (PVOID)&Expiration, &Size );
if( NO_ERROR != Error ) break;
if( Size != sizeof(Expiration) ) {
Tr("Invalid expiration\n");
Error = ERROR_INVALID_DATA;
break;
}
Size = sizeof(Type);
Error = GetColumnValue(
CLIENT_TYPE_INDEX, (PVOID)&Type, &Size );
if( NO_ERROR != Error || 0 == Size ) {
Type = CLIENT_TYPE_DHCP;
}
Size = sizeof(State);
Error = GetColumnValue(
STATE_INDEX, (PVOID)&State, &Size );
if( NO_ERROR != Error || 0 == Size ) {
State = ADDRESS_STATE_ACTIVE;
}
if( ADDRESS_STATE_OFFERED == State ) {
continue;
}
//
// Try to add the client
//
Error = AddScannedClient(
ByteSwap(IpAddress), ByteSwap(SubnetMask), HwAddress, HwLen,
MachineName, MachineInfo, *(PULONGLONG)&Expiration,
State, Type );
if( NO_ERROR != Error ) break;
}
Tr("Scanned %ld clients\n", Count );
if( JET_errNoCurrentRecord == Error ) return NO_ERROR;
if( Error < 0 ) return Error;
return NO_ERROR;
}
DWORD
DumpData(
IN LPSTR Buffer,
IN ULONG BufSize
)
{
return NO_ERROR;
}
DWORD
AddRecord(
IN LPSTR Buffer,
IN ULONG BufSize
)
{
DWORD Written, Error = NO_ERROR;
if( NULL != Buffer ) {
CopyMemory(&SaveBuf[SaveBufSize], (PVOID)&BufSize, sizeof(DWORD));
CopyMemory(&SaveBuf[SaveBufSize+sizeof(DWORD)], Buffer, BufSize );
} else {
if( 0 == SaveBufSize ) return NO_ERROR;
if( FALSE == WriteFile(
hTextFile, SaveBuf, SaveBufSize, &Written, NULL ) ) {
return GetLastError();
}
if( Written != SaveBufSize ) {
ASSERT(FALSE);
return ERROR_CAN_NOT_COMPLETE;
}
return NO_ERROR;
}
if( SaveBufSize <= SAVE_THRESHOLD ) {
SaveBufSize += BufSize + sizeof(DWORD);
} else {
if( FALSE == WriteFile(
hTextFile, SaveBuf, SaveBufSize + BufSize + sizeof(DWORD),
&Written, NULL )) {
return GetLastError();
}
if( Written != SaveBufSize + BufSize + sizeof(DWORD) ) {
ASSERT(FALSE);
return ERROR_CAN_NOT_COMPLETE;
}
SaveBufSize = 0;
}
return Error;
}
DWORD
AddRecordNoSize(
IN LPSTR Buffer,
IN ULONG BufSize
)
{
DWORD Written, Error = NO_ERROR;
if( NULL != Buffer ) {
CopyMemory(&SaveBuf[SaveBufSize], Buffer, BufSize );
} else {
if( 0 == SaveBufSize ) return NO_ERROR;
if( FALSE == WriteFile(
hTextFile, SaveBuf, SaveBufSize, &Written, NULL ) ) {
return GetLastError();
}
if( Written != SaveBufSize ) {
ASSERT(FALSE);
return ERROR_CAN_NOT_COMPLETE;
}
return NO_ERROR;
}
if( SaveBufSize <= SAVE_THRESHOLD ) {
SaveBufSize += BufSize;
} else {
if( FALSE == WriteFile(
hTextFile, SaveBuf, SaveBufSize + BufSize,
&Written, NULL )) {
return GetLastError();
}
if( Written != SaveBufSize + BufSize ) {
ASSERT(FALSE);
return ERROR_CAN_NOT_COMPLETE;
}
SaveBufSize = 0;
}
return Error;
}
DWORD
StopDhcpService(
VOID
)
{
SC_HANDLE hSc, hSvc;
DWORD Error;
Error = NO_ERROR;
hSc = NULL;
hSvc = NULL;
do {
hSc = OpenSCManager(
NULL, NULL, SC_MANAGER_CONNECT | GENERIC_READ | GENERIC_WRITE );
if( NULL == hSc ) {
Error = GetLastError();
Tr("OpenSCManager: %ld\n", Error );
break;
}
hSvc = OpenService(
hSc, TEXT("DHCPServer"), SERVICE_STOP| SERVICE_QUERY_STATUS );
if( NULL == hSvc ) {
Error = GetLastError();
Tr("OpenService: %ld\n", Error );
break;
}
while( NO_ERROR == Error ) {
SERVICE_STATUS Status;
if( FALSE == QueryServiceStatus( hSvc, &Status ) ) {
Error = GetLastError();
Tr( "QueryServiceStatus: %ld\n", Error );
break;
}
if( Status.dwCurrentState == SERVICE_STOPPED ) break;
if( Status.dwCurrentState != SERVICE_RUNNING &&
Status.dwCurrentState != SERVICE_PAUSED ) {
Tr( "Waiting, state = %ld\n", Status.dwCurrentState );
if( Status.dwWaitHint < 1000 ) {
Status.dwWaitHint = 1000;
}
if( Status.dwWaitHint > 5000 ) {
Status.dwWaitHint = 1000;
}
Sleep(Status.dwWaitHint);
} else {
Error = ControlService(
hSvc, SERVICE_CONTROL_STOP, &Status );
if( FALSE != Error ) Error = NO_ERROR;
else {
Error = GetLastError();
Tr("ControlService: %ld\n", Error );
break;
}
}
}
} while( 0 );
if( NULL != hSvc ) CloseServiceHandle( hSvc );
if( NULL != hSc ) CloseServiceHandle( hSc );
return Error;
}
DWORD
StartDhcpService(
VOID
)
{
SC_HANDLE hSc, hSvc;
DWORD Error;
Error = NO_ERROR;
hSc = NULL;
hSvc = NULL;
do {
hSc = OpenSCManager(
NULL, NULL, SC_MANAGER_CONNECT | GENERIC_READ | GENERIC_WRITE );
if( NULL == hSc ) {
Error = GetLastError();
Tr("OpenSCManager: %ld\n", Error );
break;
}
hSvc = OpenService(
hSc, TEXT("DHCPServer"), SERVICE_START| SERVICE_QUERY_STATUS );
if( NULL == hSvc ) {
Error = GetLastError();
Tr("OpenService: %ld\n", Error );
break;
}
Error = StartService( hSvc, 0, NULL );
if( FALSE == Error ) Error = GetLastError(); else Error = NO_ERROR;
if( NO_ERROR != Error ) break;
while( NO_ERROR == Error ) {
SERVICE_STATUS Status;
if( FALSE == QueryServiceStatus( hSvc, &Status ) ) {
Error = GetLastError();
Tr("QueryServiceStatus: %ld\n", Error );
break;
}
if( Status.dwCurrentState == SERVICE_RUNNING ) break;
if( Status.dwCurrentState == SERVICE_START_PENDING ) {
Tr("Sleeping %ld\n", Status.dwWaitHint );
if( Status.dwWaitHint < 1000 ) {
Status.dwWaitHint = 1000;
}
if( Status.dwWaitHint > 5000 ) {
Status.dwWaitHint = 5000;
}
Sleep(Status.dwWaitHint);
} else {
Error = ERROR_CAN_NOT_COMPLETE;
break;
}
}
} while( 0 );
if( NULL != hSvc ) CloseServiceHandle( hSvc );
if( NULL != hSc ) CloseServiceHandle( hSc );
return Error;
}
DWORD __stdcall PrintRecord(
IN PDHCP_RECORD Recx
)
{
DWORD i;
DHCP_RECORD Rec = *Recx;
if( Rec.fMcast ) {
printf("Mcast Record\n" );
printf("Address: %s\n", IpAddressToString(
Rec.Info.Mcast.Address ));
printf("ScopeId: %s\n", IpAddressToString(
Rec.Info.Mcast.ScopeId ));
printf("ClientId:");
for( i = 0 ; i < (DWORD)Rec.Info.Mcast.HwLen; i ++ ) {
printf(" %02X", Rec.Info.Mcast.ClientId[i]);
}
printf("\nState = %02X\n", Rec.Info.Mcast.State);
} else {
printf("DHCP Record\n" );
printf("Address: %s\n", IpAddressToString(
Rec.Info.Dhcp.Address ));
printf("Mask: %s\n", IpAddressToString(
Rec.Info.Dhcp.Mask ));
printf("ClientId:");
for( i = 0 ; i < (DWORD)Rec.Info.Dhcp.HwLen; i ++ ) {
printf(" %02X", Rec.Info.Dhcp.HwAddr[i]);
}
printf("\nState = %02X\n", Rec.Info.Dhcp.State);
printf("\nType = %02X\n", Rec.Info.Dhcp.Type);
if( Rec.Info.Dhcp.Name ) {
printf("Name = %ws\n", Rec.Info.Dhcp.Name );
}
if( Rec.Info.Dhcp.Info ) {
printf("Comment = %ws\n", Rec.Info.Dhcp.Info );
}
}
return NO_ERROR;
}
DWORD
StringLen(
IN WCHAR UNALIGNED *Str
)
{
DWORD Size = sizeof(WCHAR);
if( NULL == Str ) return 0;
while( *Str ++ != L'\0' ) Size += sizeof(WCHAR);
return Size;
}
DWORD __stdcall
AddRecordToDatabase(
IN PDHCP_RECORD Recx
)
{
DWORD Index;
JET_ERR Error;
DHCP_RECORD Rec = *Recx;
WCHAR Address[30], HwAddress[300];
IpAddressToStringW(Rec.Info.Dhcp.Address, Address);
DhcpHexToString(
HwAddress, Rec.Info.Dhcp.HwAddr,
Rec.Info.Dhcp.HwLen );
Error = JetBeginTransaction( JetSession );
Tr( "JetBeginTransaction: %ld\n", Error );
if( Error < 0 ) return Error;
do {
Error = JetPrepareUpdate( JetSession, JetTbl, JET_prepInsert );
if( Error ) Tr( "JetPrepareUpdate: %ld\n", Error );
if( Error < 0 ) break;
Index = IPADDRESS_INDEX;
Error = SetColumnValue(
Index, (LPBYTE)&Rec.Info.Dhcp.Address, sizeof(DWORD) );
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = SUBNET_MASK_INDEX;
Error = SetColumnValue(
Index, (LPBYTE)&Rec.Info.Dhcp.Mask, sizeof(DWORD) );
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = HARDWARE_ADDRESS_INDEX;
Error = SetColumnValue(
Index, Rec.Info.Dhcp.HwAddr, Rec.Info.Dhcp.HwLen );
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = STATE_INDEX;
Error = SetColumnValue(
Index, &Rec.Info.Dhcp.State, sizeof(BYTE) );
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = CLIENT_TYPE_INDEX;
Error = SetColumnValue(
Index, &Rec.Info.Dhcp.Type, sizeof(BYTE) );
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = MACHINE_INFO_INDEX;
Error = SetColumnValue(
Index, (LPBYTE)Rec.Info.Dhcp.Info, StringLen(Rec.Info.Dhcp.Info) );
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = MACHINE_NAME_INDEX;
Error = SetColumnValue(
Index, (LPBYTE)Rec.Info.Dhcp.Name, StringLen(Rec.Info.Dhcp.Name) );
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = LEASE_TERMINATE_INDEX;
Error = SetColumnValue(
Index, (LPBYTE)&Rec.Info.Dhcp.ExpTime, sizeof(FILETIME) );
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = SERVER_IP_ADDRESS_INDEX;
Rec.Info.Dhcp.Address = INADDR_LOOPBACK;
Error = SetColumnValue(
Index, (LPBYTE)&Rec.Info.Dhcp.Address, sizeof(DWORD));
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Index = SERVER_NAME_INDEX;
Rec.Info.Dhcp.Name = L"";
Error = SetColumnValue(
Index, (LPBYTE)Rec.Info.Dhcp.Name, StringLen(Rec.Info.Dhcp.Name));
if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
if( Error < 0 ) break;
Error = JetUpdate( JetSession, JetTbl, NULL, 0, NULL );
if( Error ) Tr( "JetUpdate: %ld\n", Error );
if( Error < 0 ) break;
} while ( 0 );
if( Error < 0 ) {
BOOL fAbort;
JetRollback( JetSession, 0 );
fAbort = TRUE;
DhcpEximErrorDatabaseEntryFailed(
Address, HwAddress, Error, &fAbort );
if( fAbort ) return ERROR_CAN_NOT_COMPLETE;
} else {
JetCommitTransaction( JetSession, 0 );
}
return NO_ERROR;
}
DWORD
ProcessDbEntries(
IN LPSTR Buffer,
IN ULONG BufSize,
IN PULONG Subnets,
IN ULONG nSubnets,
IN DHCP_ADD_RECORD_ROUTINE AddRec
)
{
DWORD Size, ThisSize, DbEntry;
LPSTR Buf;
DWORD Address, i, Error;
FILETIME Time;
DHCP_RECORD Rec;
Error = NO_ERROR;
while( BufSize > sizeof(DWORD) ) {
CopyMemory(&ThisSize, Buffer, sizeof(DWORD));
Buffer += sizeof(DWORD);
BufSize -= sizeof(DWORD);
if( ThisSize > BufSize ) return ERROR_INVALID_DATA;
if( ThisSize == 0 ) continue;
DbEntry = *Buffer;
Buf = Buffer+1;
Buffer += ThisSize;
BufSize -= ThisSize;
ZeroMemory( &Rec, sizeof(Rec));
switch(DbEntry) {
default :
return ERROR_INVALID_DATA;
case RecordTypeDbEntry :
Rec.fMcast = FALSE;
CopyMemory( &Rec.Info.Dhcp.Address, Buf, sizeof(DWORD));
Rec.Info.Dhcp.Address = ByteSwap(Rec.Info.Dhcp.Address);
Buf += sizeof(DWORD);
CopyMemory( &Rec.Info.Dhcp.Mask, Buf, sizeof(DWORD));
Rec.Info.Dhcp.Mask = ByteSwap(Rec.Info.Dhcp.Mask);
Buf += sizeof(DWORD);
Size = Rec.Info.Dhcp.HwLen = *Buf++;
Rec.Info.Dhcp.HwAddr = Buf;
Buf += Size;
CopyMemory(&Size, Buf, sizeof(DWORD));
Buf += sizeof(DWORD);
if( Size ) {
Rec.Info.Dhcp.Name = (PVOID)Buf;
Buf += Size;
}
CopyMemory(&Size, Buf, sizeof(DWORD));
Buf += sizeof(DWORD);
if( Size ) {
Rec.Info.Dhcp.Info = (PVOID)Buf;
Buf += Size;
}
CopyMemory(&Rec.Info.Dhcp.ExpTime, Buf, sizeof(FILETIME));
Buf += sizeof(FILETIME);
Rec.Info.Dhcp.State = Buf[0];
Rec.Info.Dhcp.Type = Buf[1];
//
// Add the subnet only if it is selected
//
if( !SubnetNotSelected(
Rec.Info.Dhcp.Address & Rec.Info.Dhcp.Mask,
Subnets, nSubnets ) ) {
Error = AddRec( &Rec );
}
break;
case RecordTypeMcastDbEntry :
Rec.fMcast = TRUE;
CopyMemory( &Rec.Info.Mcast.Address, Buf, sizeof(DWORD));
Buf += sizeof(DWORD);
CopyMemory( &Rec.Info.Mcast.ScopeId, Buf, sizeof(DWORD));
Buf += sizeof(DWORD);
Size = Rec.Info.Mcast.HwLen = *Buf++;
Rec.Info.Mcast.ClientId = Buf;
Buf += Size;
CopyMemory(&Size, Buf, sizeof(DWORD));
Buf += sizeof(DWORD);
if( Size ) {
Rec.Info.Mcast.Info = (PVOID)Buf;
Buf += Size;
}
CopyMemory(&Rec.Info.Mcast.End, Buf, sizeof(FILETIME));
Buf += sizeof(FILETIME);
CopyMemory(&Rec.Info.Mcast.Start, Buf, sizeof(FILETIME));
Buf += sizeof(FILETIME);
Rec.Info.Mcast.State = Buf[0];
Error = AddRec( &Rec );
break;
}
if( NO_ERROR != Error ) return Error;
}
return NO_ERROR;
}
DWORD
SaveDatabaseEntriesToFile(
IN PULONG Subnets,
IN ULONG nSubnets
)
{
DWORD Error;
Error = InitializeDatabase();
if( NO_ERROR != Error ) {
Tr("InitializeDatabase: %ld\n", Error );
return Error;
}
Error = ScanDatabase(Subnets, nSubnets);
if( NO_ERROR != Error ) {
Tr("ScanDatabase: %ld\n", Error);
} else {
AddRecord( NULL, 0 );
}
CleanupDatabase();
return Error;
}
DWORD
SaveFileEntriesToDatabase(
IN LPBYTE Mem,
IN ULONG MemSize,
IN PULONG Subnets,
IN ULONG nSubnets
)
{
DWORD Error;
Error = InitializeDatabase();
if( NO_ERROR != Error ) {
Tr("InitializeDatabase: %ld\n", Error );
return Error;
}
Error = ProcessDbEntries(
Mem, MemSize, Subnets, nSubnets, AddRecordToDatabase );
if( NO_ERROR != Error ) {
Tr("ProcessDbEntries: %ld\n", Error );
}
CleanupDatabase();
return Error;
}
DWORD
InitializeDatabaseParameters(
VOID
)
{
DWORD Error;
//
// Stop the service
//
Error = StopDhcpService();
if( NO_ERROR != Error ) {
Tr("StopDhcpService: %ld\n", Error );
return Error;
}
//
// Read the registry and otherwise initialize the database
// parameters, without actually opening the database.
//
Error = ReadRegistry();
Tr("ReadRegistry: %ld\n", Error );
if( NO_ERROR != Error ) return Error;
Error = ConvertPermissionsOnDbFiles();
Tr("ConvertPermissionsOnDbFiles: %ld\n", Error );
// ignore error and try best effort
if( FALSE == SetCurrentDirectoryA(DatabasePath) ) {
Error = GetLastError();
if( ERROR_FILE_NOT_FOUND == Error ||
ERROR_PATH_NOT_FOUND == Error ) {
return ERROR_SERVICE_DOES_NOT_EXIST;
}
return Error;
}
return NO_ERROR;
}
DWORD
CleanupDatabaseParameters(
VOID
)
{
DWORD Error;
Error = StartDhcpService();
if( NO_ERROR != Error ) {
Tr("StartDhcpService: %ld\n", Error );
}
return Error;
}