/*++ Copyright (C) 1999 Microsoft Coporation Module Name: db2file.c Abstract: This module reads the database records and writes them into a file format. --*/ #include 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_coltypLongBinary }, { 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_coltypLongBinary }, { 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; memcpy( Temp, DbPath, (( sizeof( Temp ) - 1 ) < strlen( DbPath )) ? sizeof( Temp ) : strlen( DbPath ) + 1 ); Temp[ sizeof( Temp ) - 2 ] = '\0'; 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; DWORD Len, Len1; 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; Error = JetDetachDatabase( JetSession, NULL ); Tr("JetDetachDatabase:%ld\n", Error ); if( Error < 0 ) return Error; // Create the filename Len = strlen( DbName ); Len1 = strlen( DbPath ); if ( sizeof( FilePath ) < ( Len + Len1 + 2 )) { // 2 for '\\' and '\0' return ERROR_INVALID_PARAMETER; } memcpy( FilePath, DbPath, Len1 ); FilePath[ Len1 ] = '\\'; memcpy( FilePath + Len1 + 1, DbName, Len ); FilePath[ Len + Len1 + 1 ] = '\0'; Error = JetAttachDatabase( JetSession, FilePath, JET_bitDbExclusive ); 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); if ( NULL != MachineName ) { 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); if ( NULL != MachineInfo ) { 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; }