Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2016 lines
50 KiB

  1. /*++
  2. Copyright (C) 1999 Microsoft Coporation
  3. Module Name:
  4. db2file.c
  5. Abstract:
  6. This module reads the database records and writes them into a
  7. file format.
  8. --*/
  9. #include <precomp.h>
  10. enum {
  11. RecordTypeDbEntry,
  12. RecordTypeMcastDbEntry,
  13. };
  14. //
  15. // database table and field names.
  16. //
  17. #define IPADDRESS_INDEX 0
  18. #define HARDWARE_ADDRESS_INDEX 1
  19. #define STATE_INDEX 2
  20. #define MACHINE_INFO_INDEX 3
  21. #define MACHINE_NAME_INDEX 4
  22. #define LEASE_TERMINATE_INDEX 5
  23. #define SUBNET_MASK_INDEX 6
  24. #define SERVER_IP_ADDRESS_INDEX 7
  25. #define SERVER_NAME_INDEX 8
  26. #define CLIENT_TYPE_INDEX 9
  27. #define MAX_INDEX 10
  28. #define SAVE_THRESHOLD (1000000L)
  29. //
  30. // Globals
  31. //
  32. DWORD JetVersion;
  33. CHAR DatabaseName[1024], DatabasePath[1024];
  34. HMODULE hJet;
  35. JET_INSTANCE JetInstance;
  36. JET_SESID JetSession;
  37. JET_DBID JetDb;
  38. JET_TABLEID JetTbl;
  39. PUCHAR SaveBuf;
  40. ULONG SaveBufSize;
  41. HANDLE hTextFile, hMapping;
  42. PVOID FileView;
  43. WCHAR Winnt32Path[MAX_PATH*2];
  44. CHAR System32Path[MAX_PATH*2];
  45. JET_ERR (JET_API *pJetSetCurrentIndex)(
  46. JET_SESID sesid,
  47. JET_TABLEID tableid,
  48. const char *szIndexName
  49. );
  50. JET_ERR (JET_API *pJetRetrieveColumn)(
  51. JET_SESID sesid,
  52. JET_TABLEID tableid,
  53. JET_COLUMNID columnid,
  54. void *pvData,
  55. unsigned long cbData,
  56. unsigned long *pcbActual,
  57. JET_GRBIT grbit,
  58. JET_RETINFO *pretinfo );
  59. JET_ERR (JET_API *pJetSetColumn)(
  60. JET_SESID sesid,
  61. JET_TABLEID tableid,
  62. JET_COLUMNID columnid,
  63. const void *pvData,
  64. unsigned long cbData,
  65. JET_GRBIT grbit,
  66. JET_SETINFO *psetinfo );
  67. JET_ERR (JET_API *pJetMove)(
  68. JET_SESID sesid,
  69. JET_TABLEID tableid,
  70. long cRow,
  71. JET_GRBIT grbit );
  72. JET_ERR (JET_API *pJetSetSystemParameter)(
  73. JET_INSTANCE *pinstance,
  74. JET_SESID sesid,
  75. unsigned long paramid,
  76. ULONG_PTR lParam,
  77. const char *sz );
  78. JET_ERR (JET_API *pJetBeginTransaction)(
  79. JET_SESID sesid
  80. );
  81. JET_ERR (JET_API *pJetPrepareUpdate)(
  82. JET_SESID sesid,
  83. JET_TABLEID tableid,
  84. unsigned long prep );
  85. JET_ERR (JET_API *pJetUpdate)(
  86. JET_SESID sesid,
  87. JET_TABLEID tableid,
  88. void *pvBookmark,
  89. unsigned long cbBookmark,
  90. unsigned long *pcbActual);
  91. JET_ERR (JET_API *pJetCommitTransaction)( JET_SESID sesid, JET_GRBIT grbit );
  92. JET_ERR (JET_API *pJetRollback)( JET_SESID sesid, JET_GRBIT grbit );
  93. JET_ERR (JET_API *pJetTerm)( JET_INSTANCE instance );
  94. JET_ERR (JET_API *pJetTerm2)( JET_INSTANCE instance, JET_GRBIT grbit );
  95. JET_ERR (JET_API *pJetEndSession)( JET_SESID sesid, JET_GRBIT grbit );
  96. JET_ERR (JET_API *pJetBeginSession)(
  97. JET_INSTANCE instance,
  98. JET_SESID *psesid,
  99. const char *szUserName,
  100. const char *szPassword );
  101. JET_ERR (JET_API *pJetInit)( JET_INSTANCE *pinstance);
  102. JET_ERR (JET_API *pJetDetachDatabase)(
  103. JET_SESID sesid,
  104. const char *szFilename );
  105. JET_ERR (JET_API *pJetAttachDatabase)(
  106. JET_SESID sesid,
  107. const char *szFilename,
  108. JET_GRBIT grbit );
  109. JET_ERR (JET_API *pJetOpenDatabase)(
  110. JET_SESID sesid,
  111. const char *szFilename,
  112. const char *szConnect,
  113. JET_DBID *pdbid,
  114. JET_GRBIT grbit );
  115. JET_ERR (JET_API *pJetCloseDatabase)(
  116. JET_SESID sesid,
  117. JET_DBID dbid,
  118. JET_GRBIT grbit );
  119. JET_ERR (JET_API *pJetOpenTable)(
  120. JET_SESID sesid,
  121. JET_DBID dbid,
  122. const char *szTableName,
  123. const void *pvParameters,
  124. unsigned long cbParameters,
  125. JET_GRBIT grbit,
  126. JET_TABLEID *ptableid );
  127. JET_ERR (JET_API *pJetCloseTable)( JET_SESID sesid, JET_TABLEID tableid );
  128. JET_ERR (JET_API *pJetGetTableColumnInfo)(
  129. JET_SESID sesid,
  130. JET_TABLEID tableid,
  131. const char *szColumnName,
  132. void *pvResult,
  133. unsigned long cbMax,
  134. unsigned long InfoLevel );
  135. JET_ERR (JET_API *pJetGetIndexInfo)(
  136. JET_SESID sesid,
  137. JET_DBID dbid,
  138. const char *szTableName,
  139. const char *szIndexName,
  140. void *pvResult,
  141. unsigned long cbResult,
  142. unsigned long InfoLevel );
  143. #define DB_FUNC(F,I,S) \
  144. {#F, TEXT(#F), #F "@" #S, I, (FARPROC *)& p ## F }
  145. typedef struct _DB_FUNC_ENTRY {
  146. LPSTR FuncName;
  147. LPWSTR FuncNameW;
  148. LPSTR AltName;
  149. DWORD Index;
  150. FARPROC *FuncPtr;
  151. } DB_FUNC_ENTRY;
  152. DB_FUNC_ENTRY FuncTable[] = {
  153. DB_FUNC(JetSetCurrentIndex, 164, 12),
  154. DB_FUNC(JetRetrieveColumn, 157, 32),
  155. DB_FUNC(JetSetColumn, 162, 28),
  156. DB_FUNC(JetMove, 147, 16),
  157. DB_FUNC(JetSetSystemParameter, 165, 20),
  158. DB_FUNC(JetTerm, 167, 4),
  159. DB_FUNC(JetTerm2, 0, 8),
  160. DB_FUNC(JetEndSession, 124, 8),
  161. DB_FUNC(JetBeginSession, 104, 16),
  162. DB_FUNC(JetInit, 145, 4),
  163. DB_FUNC(JetDetachDatabase, 121, 8),
  164. DB_FUNC(JetAttachDatabase, 102, 12),
  165. DB_FUNC(JetOpenDatabase, 148, 20),
  166. DB_FUNC(JetOpenTable, 149, 28),
  167. DB_FUNC(JetGetTableColumnInfo, 137, 24),
  168. DB_FUNC(JetCloseTable,108, 8),
  169. DB_FUNC(JetCloseDatabase, 107, 12),
  170. DB_FUNC(JetGetIndexInfo, 131, 28),
  171. DB_FUNC(JetBeginTransaction, 105, 4),
  172. DB_FUNC(JetPrepareUpdate, 151, 12),
  173. DB_FUNC(JetUpdate, 168, 20),
  174. DB_FUNC(JetCommitTransaction, 109, 8),
  175. DB_FUNC(JetRollback, 160, 8),
  176. };
  177. #define JetSetCurrentIndex pJetSetCurrentIndex
  178. #define JetRetrieveColumn pJetRetrieveColumn
  179. #define JetSetColumn pJetSetColumn
  180. #define JetMove pJetMove
  181. #define JetSetSystemParameter pJetSetSystemParameter
  182. #define JetTerm pJetTerm
  183. #define JetTerm2 pJetTerm2
  184. #define JetEndSession pJetEndSession
  185. #define JetBeginSession pJetBeginSession
  186. #define JetInit pJetInit
  187. #define JetDetachDatabase pJetDetachDatabase
  188. #define JetAttachDatabase pJetAttachDatabase
  189. #define JetOpenDatabase pJetOpenDatabase
  190. #define JetOpenTable pJetOpenTable
  191. #define JetGetTableColumnInfo pJetGetTableColumnInfo
  192. #define JetCloseTable pJetCloseTable
  193. #define JetCloseDatabase pJetCloseDatabase
  194. #define JetGetIndexInfo pJetGetIndexInfo
  195. #define JetBeginTransaction pJetBeginTransaction
  196. #define JetPrepareUpdate pJetPrepareUpdate
  197. #define JetUpdate pJetUpdate
  198. #define JetCommitTransaction pJetCommitTransaction
  199. #define JetRollback pJetRollback
  200. typedef struct _TABLE_INFO {
  201. CHAR *ColName;
  202. JET_COLUMNID ColHandle;
  203. BOOL fPresent;
  204. JET_COLTYP ColType;
  205. } TABLE_INFO, *LPTABLE_INFO;
  206. #define IPADDRESS_STRING "IpAddress"
  207. #define HARDWARE_ADDRESS_STRING "HardwareAddress"
  208. #define STATE_STRING "State"
  209. #define MACHINE_INFO_STRING "MachineInformation"
  210. #define MACHINE_NAME_STRING "MachineName"
  211. #define LEASE_TERMINATE_STRING "LeaseTerminates"
  212. #define SUBNET_MASK_STRING "SubnetMask"
  213. #define SERVER_IP_ADDRESS_STRING "ServerIpAddress"
  214. #define SERVER_NAME_STRING "ServerName"
  215. #define CLIENT_TYPE "ClientType"
  216. static TABLE_INFO ClientTable[] = {
  217. { IPADDRESS_STRING , 0, 1, JET_coltypLong },
  218. { HARDWARE_ADDRESS_STRING , 0, 1, JET_coltypBinary },
  219. { STATE_STRING , 0, 1, JET_coltypUnsignedByte },
  220. { MACHINE_INFO_STRING , 0, 1, JET_coltypBinary }, // must modify MACHINE_INFO_SIZE if this changes
  221. { MACHINE_NAME_STRING , 0, 1, JET_coltypBinary },
  222. { LEASE_TERMINATE_STRING , 0, 1, JET_coltypCurrency },
  223. { SUBNET_MASK_STRING , 0, 1, JET_coltypLong },
  224. { SERVER_IP_ADDRESS_STRING, 0, 1, JET_coltypLong },
  225. { SERVER_NAME_STRING , 0, 1, JET_coltypBinary },
  226. { CLIENT_TYPE , 0, 1, JET_coltypUnsignedByte }
  227. };
  228. #define MAGIC_COOKIE_NT4 'NT4 '
  229. #define MAGIC_COOKIE_NT5 'W2K '
  230. #define MAGIC_COOKIE_NT5_PLUS 'W2K1'
  231. DWORD
  232. GetCurrentMagicCookie(
  233. VOID
  234. )
  235. {
  236. OSVERSIONINFO Ver;
  237. Ver.dwOSVersionInfoSize = sizeof(Ver);
  238. if( FALSE == GetVersionEx(&Ver) ) return MAGIC_COOKIE_NT5_PLUS;
  239. if( Ver.dwMajorVersion == 4 ) return MAGIC_COOKIE_NT4;
  240. else if( Ver.dwMajorVersion == 5 ) {
  241. if( Ver.dwBuildNumber >= 2200 ) return MAGIC_COOKIE_NT5_PLUS;
  242. else return MAGIC_COOKIE_NT5;
  243. }
  244. return MAGIC_COOKIE_NT4;
  245. }
  246. DWORD
  247. OpenTextFile(
  248. IN LPWSTR FileName,
  249. IN BOOL fRead,
  250. OUT HANDLE *hFile,
  251. OUT LPBYTE *Mem,
  252. OUT ULONG *MemSize
  253. )
  254. {
  255. DWORD Error, Flags, LoSize, HiSize;
  256. Flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN;
  257. hTextFile = CreateFileW(
  258. FileName, GENERIC_READ | GENERIC_WRITE | DELETE,
  259. FILE_SHARE_READ, NULL,
  260. fRead ? OPEN_EXISTING : CREATE_ALWAYS,
  261. Flags, NULL );
  262. if( hTextFile == INVALID_HANDLE_VALUE ) {
  263. hTextFile = NULL;
  264. Error = GetLastError();
  265. if( !fRead || ERROR_FILE_NOT_FOUND != Error ) {
  266. Tr("CreateFile<%ws>: %ld\n", FileName, Error );
  267. }
  268. return Error;
  269. }
  270. (*hFile) = hTextFile;
  271. if( !fRead ) {
  272. //
  273. // Write the magic cookie
  274. //
  275. Flags = GetCurrentMagicCookie();
  276. if( FALSE == WriteFile(
  277. hTextFile, (LPBYTE)&Flags, sizeof(Flags), &LoSize,
  278. NULL ) ) {
  279. Error = GetLastError();
  280. CloseHandle(hTextFile);
  281. return Error;
  282. }
  283. return NO_ERROR;
  284. }
  285. LoSize = GetFileSize( hTextFile, &HiSize );
  286. if( -1 == LoSize && NO_ERROR != GetLastError() ) {
  287. return GetLastError();
  288. }
  289. if( LoSize <= sizeof(DWORD) ) {
  290. CloseHandle(hTextFile);
  291. return ERROR_INVALID_DATA;
  292. }
  293. (*MemSize) = LoSize;
  294. (*Mem) = NULL;
  295. hMapping = CreateFileMapping(
  296. hTextFile, NULL, PAGE_READONLY | SEC_COMMIT, HiSize, LoSize,
  297. NULL );
  298. if( NULL == hMapping ) {
  299. Error = GetLastError();
  300. Tr("Can't map file: %ld\n", Error );
  301. return Error;
  302. }
  303. FileView = MapViewOfFile(
  304. hMapping, FILE_MAP_READ, 0, 0, 0 );
  305. if( NULL == FileView ) {
  306. Error = GetLastError();
  307. Tr("Can't create view: %ld\n", Error );
  308. CloseHandle( hMapping );
  309. CloseHandle( hTextFile );
  310. hTextFile = NULL;
  311. hMapping = NULL;
  312. return Error;
  313. }
  314. (*Mem) = FileView;
  315. //
  316. // Before okaying, check if the version of the file is
  317. // greater than current version
  318. //
  319. Error = NO_ERROR;
  320. CopyMemory(&Flags, *Mem, sizeof(Flags));
  321. switch(GetCurrentMagicCookie()) {
  322. case MAGIC_COOKIE_NT5_PLUS :
  323. if( Flags != MAGIC_COOKIE_NT5 &&
  324. Flags != MAGIC_COOKIE_NT5_PLUS &&
  325. Flags != MAGIC_COOKIE_NT4 ) {
  326. Error = ERROR_NOT_SUPPORTED;
  327. }
  328. break;
  329. case MAGIC_COOKIE_NT5 :
  330. if( Flags != MAGIC_COOKIE_NT5 &&
  331. Flags != MAGIC_COOKIE_NT4 ) {
  332. Error = ERROR_NOT_SUPPORTED;
  333. }
  334. break;
  335. case MAGIC_COOKIE_NT4 :
  336. if( Flags != MAGIC_COOKIE_NT4 ) {
  337. Error = ERROR_NOT_SUPPORTED;
  338. }
  339. break;
  340. }
  341. if( NO_ERROR != Error ) {
  342. UnmapViewOfFile(FileView);
  343. CloseHandle( hMapping );
  344. CloseHandle( hTextFile );
  345. hTextFile = NULL;
  346. hMapping = NULL;
  347. FileView = NULL;
  348. return Error;
  349. }
  350. *MemSize -= sizeof(DWORD);
  351. (*Mem) += sizeof(DWORD);
  352. return NO_ERROR;
  353. }
  354. VOID
  355. CloseTextFile(
  356. IN OUT HANDLE hFile,
  357. IN OUT LPBYTE Mem
  358. )
  359. {
  360. ASSERT( hFile == hTextFile );
  361. if( NULL != FileView ) UnmapViewOfFile( FileView );
  362. FileView = NULL;
  363. if( NULL != hMapping ) CloseHandle( hMapping );
  364. hMapping = NULL;
  365. if( NULL != hTextFile ) CloseHandle( hTextFile );
  366. hTextFile = NULL;
  367. }
  368. ULONG
  369. ByteSwap(
  370. IN ULONG Source
  371. )
  372. {
  373. ULONG swapped;
  374. swapped = ((Source) << (8 * 3)) |
  375. ((Source & 0x0000FF00) << (8 * 1)) |
  376. ((Source & 0x00FF0000) >> (8 * 1)) |
  377. ((Source) >> (8 * 3));
  378. return swapped;
  379. }
  380. LPSTR
  381. IpAddressToString(
  382. IN ULONG Address
  383. )
  384. {
  385. static CHAR Buffer[30];
  386. PUCHAR pAddress;
  387. pAddress = (PUCHAR)&Address;
  388. sprintf(Buffer, "%d.%d.%d.%d", pAddress[0], pAddress[1],
  389. pAddress[2], pAddress[3] );
  390. return Buffer;
  391. }
  392. VOID static
  393. CleanupDatabase(
  394. VOID
  395. )
  396. {
  397. if( JetTbl != 0 ) {
  398. JetCloseTable( JetSession, JetTbl );
  399. JetTbl = 0;
  400. }
  401. if( JetSession != 0 ) {
  402. JetEndSession( JetSession, 0 );
  403. JetSession = 0;
  404. }
  405. if( NULL != hJet ) {
  406. if( NULL != JetTerm2 ) {
  407. JetTerm2( JetInstance, JET_bitTermComplete );
  408. } else {
  409. JetTerm( JetInstance );
  410. }
  411. FreeLibrary( hJet ); hJet = NULL;
  412. }
  413. JetInstance = 0;
  414. }
  415. DWORD
  416. LoadAndLinkRoutines(
  417. IN DWORD JetVersion
  418. )
  419. {
  420. DWORD Error, i;
  421. LPTSTR Module;
  422. LPSTR FuncName;
  423. Module = NULL;
  424. switch( JetVersion ) {
  425. case LoadJet2001 : Module = TEXT("esent.dll"); break;
  426. case LoadJet97 : Module = TEXT("esent.dll"); break;
  427. case LoadJet500 : Module = TEXT("jet500.dll"); break;
  428. case LoadJet200 : Module = TEXT("jet.dll"); break;
  429. default: Module = TEXT("esent.dll"); break;
  430. }
  431. hJet = LoadLibrary( Module );
  432. if( NULL == hJet ) {
  433. Error = GetLastError();
  434. } else {
  435. Error = NO_ERROR;
  436. }
  437. Tr( "Loading %ws: %ld\n", Module, Error );
  438. if( NO_ERROR != Error ) return Error;
  439. for( i = 0; i < sizeof(FuncTable)/sizeof(FuncTable[0]); i ++ ) {
  440. (*FuncTable[i].FuncPtr) = NULL;
  441. }
  442. for( i = 0; i < sizeof(FuncTable)/sizeof(FuncTable[0]); i ++ ) {
  443. if( LoadJet200 != JetVersion ) {
  444. FuncName = FuncTable[i].FuncName;
  445. } else {
  446. if( 0 == FuncTable[i].Index ) {
  447. (*FuncTable[i].FuncPtr) = NULL;
  448. continue;
  449. }
  450. FuncName = (LPSTR)ULongToPtr(FuncTable[i].Index);
  451. }
  452. Error = NO_ERROR;
  453. (*FuncTable[i].FuncPtr) = GetProcAddress(hJet, FuncName);
  454. if( NULL == FuncTable[i].FuncPtr ) {
  455. Error = GetLastError();
  456. if( LoadJet97 == JetVersion || LoadJet2001 == JetVersion ) {
  457. (*FuncTable[i].FuncPtr) = GetProcAddress(
  458. hJet, FuncTable[i].AltName );
  459. if( NULL != FuncTable[i].FuncPtr ) continue;
  460. Error = GetLastError();
  461. }
  462. }
  463. Tr("GetProcAddr[%ws]: %ld\n", FuncTable[i].FuncNameW, Error );
  464. if( NO_ERROR != Error ) break;
  465. }
  466. //
  467. // if erred out, cleanup
  468. //
  469. if( NO_ERROR != Error ) {
  470. FreeLibrary( hJet );
  471. hJet = NULL;
  472. }
  473. return Error;
  474. }
  475. DWORD
  476. SetJetParams(
  477. IN DWORD JetVersion,
  478. IN LPSTR DbName,
  479. IN LPSTR DbPath
  480. )
  481. {
  482. DWORD Error, JetParam, LogFileSize;
  483. CHAR Temp[2048];
  484. LPSTR DbSysFile = "\\system.mdb";
  485. LPSTR DbBaseName = "j50";
  486. JetInstance = 0;
  487. LogFileSize = 1000;
  488. if( JetVersion == LoadJet2001 ) LogFileSize = 1024;
  489. strcpy(Temp, DbPath);
  490. if( LoadJet200 == JetVersion ) {
  491. strcat(Temp, DbSysFile);
  492. JetParam = JET_paramSysDbPath_OLD;
  493. } else {
  494. strcat(Temp, "\\");
  495. if( LoadJet97 > JetVersion ) {
  496. JetParam = JET_paramSystemPath_OLD;
  497. } else {
  498. JetParam = JET_paramSystemPath;
  499. }
  500. }
  501. Error = JetSetSystemParameter(
  502. &JetInstance, (JET_SESID)0, JetParam, 0, Temp );
  503. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  504. if( NO_ERROR != Error ) return Error;
  505. if( LoadJet200 != JetVersion ) {
  506. if( LoadJet97 > JetVersion ) {
  507. JetParam = JET_paramBaseName_OLD;
  508. } else {
  509. JetParam = JET_paramBaseName;
  510. }
  511. Error = JetSetSystemParameter(
  512. &JetInstance, (JET_SESID)0, JetParam, 0, DbBaseName );
  513. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  514. if( NO_ERROR != Error ) return Error;
  515. }
  516. if( LoadJet200 != JetVersion ) {
  517. if( LoadJet97 <= JetVersion ) {
  518. JetParam = JET_paramLogFileSize;
  519. } else {
  520. JetParam = JET_paramLogFileSize_OLD;
  521. }
  522. Error = JetSetSystemParameter(
  523. &JetInstance, (JET_SESID)0, JetParam, LogFileSize, NULL );
  524. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  525. if( NO_ERROR != Error ) return Error;
  526. }
  527. if( LoadJet200 != JetVersion ) {
  528. Error = JetSetSystemParameter(
  529. &JetInstance, (JET_SESID)0,
  530. JET_paramCheckFormatWhenOpenFail, 1, NULL );
  531. JetParam = JET_paramCheckFormatWhenOpenFail;
  532. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  533. if( NO_ERROR != Error ) return Error;
  534. }
  535. if( LoadJet200 != JetVersion ) {
  536. if( LoadJet97 > JetVersion ) {
  537. JetParam = JET_paramRecovery_OLD;
  538. } else {
  539. JetParam = JET_paramRecovery;
  540. }
  541. Error = JetSetSystemParameter(
  542. &JetInstance, (JET_SESID)0, JetParam, 0, "on");
  543. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  544. if( NO_ERROR != Error ) return Error;
  545. }
  546. //
  547. // Note: Ideally, the log files should never exist. Even
  548. // if the database is opened in readonly mode, they seem to
  549. // exist. Not sure what else can be done
  550. //
  551. if( LoadJet97 <= JetVersion ) {
  552. JetParam = JET_paramLogFilePath;
  553. } else {
  554. JetParam = JET_paramLogFilePath_OLD;
  555. }
  556. strcpy(Temp, DbPath); strcat( Temp, "\\");
  557. Error = JetSetSystemParameter(
  558. &JetInstance, (JET_SESID)0, JetParam, 0, Temp );
  559. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  560. return Error;
  561. }
  562. DWORD
  563. OpenDatabase(
  564. IN DWORD JetVersion,
  565. IN LPSTR DbName,
  566. IN LPSTR DbPath
  567. )
  568. {
  569. LONG Error;
  570. DWORD i;
  571. CHAR FilePath[2048];
  572. JET_INDEXLIST TmpIdxList;
  573. JetSession = 0;
  574. JetDb = 0;
  575. JetTbl = 0;
  576. Error = JetInit( &JetInstance );
  577. Tr("JetInit: %ld\n", Error );
  578. if( NO_ERROR != Error ) return Error;
  579. Error = JetBeginSession(
  580. JetInstance, &JetSession, "admin", "" );
  581. Tr("JetBeginSession: %ld\n", Error);
  582. if( Error < 0 ) return Error;
  583. strcpy(FilePath, DbPath );
  584. strcat(FilePath, "\\" );
  585. //
  586. // fix prefast bug 292432
  587. //
  588. if ( strlen( DbName ) < ( 2048 - strlen( FilePath ) ) )
  589. strcat(FilePath, DbName );
  590. Error = JetDetachDatabase( JetSession, NULL );
  591. Tr("JetDetachDatabase:%ld\n", Error );
  592. if( Error < 0 ) return Error;
  593. Error = JetAttachDatabase( JetSession, FilePath, JET_bitDbRecoveryOff );
  594. Tr("JetAttachDatabase:%ld\n", Error );
  595. if( Error < 0 ) return Error;
  596. Error = JetOpenDatabase(
  597. JetSession, FilePath, NULL, &JetDb,
  598. JET_bitDbSingleExclusive );
  599. Tr("JetOpenDatabase: %ld\n", Error);
  600. if( Error < 0 ) return Error;
  601. Error = JetOpenTable(
  602. JetSession, JetDb, (LPSTR)"ClientTable",
  603. NULL, 0, 0,&JetTbl );
  604. Tr("JetOpenTable: %ld\n", Error );
  605. if( Error < 0 ) return Error;
  606. for( i = 0; i < sizeof(ClientTable)/sizeof(ClientTable[0]); i ++ ) {
  607. JET_COLUMNDEF ColDef;
  608. Error = JetGetTableColumnInfo(
  609. JetSession, JetTbl, ClientTable[i].ColName, &ColDef,
  610. sizeof(ColDef), 0 );
  611. if(Error && JET_errColumnNotFound != Error ) {
  612. Tr("JetGetCol: %ld\n", Error );
  613. }
  614. if( Error < 0 ) {
  615. if( JET_errColumnNotFound == Error ) {
  616. ClientTable[i].fPresent = FALSE;
  617. continue;
  618. } else {
  619. return Error;
  620. }
  621. }
  622. if( ColDef.coltyp != ClientTable[i].ColType ) {
  623. ASSERT( FALSE );
  624. Error = ERROR_BAD_FORMAT;
  625. return Error;
  626. }
  627. ClientTable[i].ColHandle = ColDef.columnid;
  628. }
  629. return NO_ERROR;
  630. }
  631. DWORD
  632. LoadAndInitializeDatabase(
  633. IN DWORD JetVersion,
  634. IN LPSTR DbName,
  635. IN LPSTR DbPath
  636. )
  637. {
  638. DWORD Error;
  639. //
  640. // Attempt to load DLL and retrieve function pointers
  641. //
  642. Tr("Loading %ld jet version\n", JetVersion );
  643. Error = LoadAndLinkRoutines( JetVersion );
  644. if( NO_ERROR != Error ) return Error;
  645. //
  646. // set standard jet params
  647. //
  648. Error = SetJetParams( JetVersion, DbName, DbPath );
  649. if( NO_ERROR != Error ) {
  650. FreeLibrary( hJet ); hJet = NULL;
  651. return Error;
  652. }
  653. //
  654. // Attempt to open database
  655. //
  656. Error = OpenDatabase( JetVersion, DbName, DbPath );
  657. if( NO_ERROR != Error ) {
  658. CleanupDatabase();
  659. return Error;
  660. }
  661. return NO_ERROR;
  662. }
  663. DWORD
  664. LoadAndLinkSecurityRoutines(
  665. OUT FARPROC *pGetInfo,
  666. OUT FARPROC *pSetInfo
  667. )
  668. {
  669. HMODULE hAdvapi32;
  670. hAdvapi32 = GetModuleHandle(TEXT("ADVAPI32.DLL"));
  671. if( NULL == hAdvapi32 ) return GetLastError();
  672. (*pGetInfo) = GetProcAddress(hAdvapi32, "GetNamedSecurityInfoA");
  673. if( NULL == *pGetInfo ) return GetLastError();
  674. (*pSetInfo) = GetProcAddress(hAdvapi32, "SetNamedSecurityInfoA");
  675. if( NULL == *pSetInfo ) return GetLastError();
  676. return NO_ERROR;
  677. }
  678. DWORD
  679. ConvertPermissionsOnDbFiles(
  680. VOID
  681. )
  682. {
  683. DWORD Error, dwVersion = GetVersion();
  684. PSECURITY_DESCRIPTOR pSec;
  685. PACL pAcl;
  686. HANDLE hSearch = INVALID_HANDLE_VALUE;
  687. WIN32_FIND_DATAA FileData;
  688. CHAR FileName[1024];
  689. FARPROC pGetInfo, pSetInfo;
  690. CHAR DriversDirPath[MAX_PATH *2 +1];
  691. DWORD PathLen = sizeof(DriversDirPath)-1;
  692. //
  693. // Check if version is atleast NT5.
  694. //
  695. dwVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
  696. if( dwVersion < 5 ) return NO_ERROR;
  697. //
  698. // First get the requried function pointers..
  699. //
  700. Error = LoadAndLinkSecurityRoutines(
  701. &pGetInfo, &pSetInfo );
  702. if( NO_ERROR != Error ) return Error;
  703. ZeroMemory(DriversDirPath, PathLen+1);
  704. PathLen = ExpandEnvironmentStringsA(
  705. "%SystemRoot%\\system32\\drivers", DriversDirPath, PathLen );
  706. if( PathLen == 0 ) {
  707. Error = GetLastError();
  708. return Error;
  709. }
  710. pSec = NULL;
  711. pAcl = NULL;
  712. Error = (DWORD)pGetInfo(
  713. DriversDirPath, //"MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer",
  714. SE_FILE_OBJECT, // SE_REGISTRY_KEY
  715. DACL_SECURITY_INFORMATION, NULL, NULL,
  716. &pAcl, NULL, &pSec );
  717. if( NO_ERROR != Error ) return Error;
  718. Error = (DWORD)pSetInfo(
  719. DatabasePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
  720. NULL, NULL, pAcl, NULL );
  721. if( NO_ERROR != Error ) return Error;
  722. strcpy(FileName, DatabasePath);
  723. if( FileName[strlen(FileName)-1] != '\\' ) {
  724. strcat(FileName, "\\");
  725. }
  726. strcat(FileName, DatabaseName);
  727. Error = (DWORD)pSetInfo(
  728. FileName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
  729. NULL, NULL, pAcl, NULL );
  730. if( NO_ERROR != Error ) goto Cleanup;
  731. //
  732. // Now for all files matching "*.log", repeat above operation
  733. //
  734. strcpy(FileName, DatabasePath);
  735. if( FileName[strlen(FileName)-1] != '\\' ) {
  736. strcat(FileName, "\\");
  737. }
  738. strcat(FileName, "*.*");
  739. hSearch = FindFirstFileA( FileName, &FileData );
  740. if( INVALID_HANDLE_VALUE == hSearch ) {
  741. Error = GetLastError();
  742. goto Cleanup;
  743. }
  744. do {
  745. if( 0 != strcmp(FileData.cFileName, ".") &&
  746. 0 != strcmp(FileData.cFileName, "..") ) {
  747. strcpy(FileName, DatabasePath);
  748. if( FileName[strlen(FileName)-1] != '\\' ) {
  749. strcat(FileName, "\\");
  750. }
  751. strcat(FileName, FileData.cFileName);
  752. Error = (DWORD)pSetInfo(
  753. FileName, SE_FILE_OBJECT,
  754. DACL_SECURITY_INFORMATION, NULL, NULL, pAcl, NULL );
  755. if( NO_ERROR != Error ) break;
  756. }
  757. Error = FindNextFileA( hSearch, &FileData );
  758. if( FALSE != Error ) Error = NO_ERROR;
  759. else Error = GetLastError();
  760. } while( NO_ERROR == Error );
  761. FindClose( hSearch );
  762. Cleanup:
  763. LocalFree( pSec );
  764. if( ERROR_FILE_NOT_FOUND == Error ) return NO_ERROR;
  765. if( ERROR_NO_MORE_FILES == Error ) return NO_ERROR;
  766. return Error;
  767. }
  768. DWORD
  769. ReadString(
  770. IN HKEY hKey,
  771. IN LPSTR KeyName,
  772. IN LPSTR Buffer,
  773. IN ULONG BufSize
  774. )
  775. {
  776. DWORD Error, Size, Type;
  777. CHAR Str[1024];
  778. Size = sizeof(Str);
  779. Error = RegQueryValueExA(
  780. hKey, KeyName, NULL, &Type, (LPSTR)Str, &Size );
  781. if( NO_ERROR == Error ) {
  782. if( 0 == Size || 1 == Size ) Error = ERROR_NOT_FOUND;
  783. if( Type != REG_SZ && Type != REG_EXPAND_SZ && Type !=
  784. REG_MULTI_SZ ) Error = ERROR_BAD_FORMAT;
  785. }
  786. if( NO_ERROR != Error ) return Error;
  787. Size = ExpandEnvironmentStringsA( (LPSTR)Str, Buffer, BufSize );
  788. if( Size == 0 || Size > BufSize ) {
  789. Error = ERROR_META_EXPANSION_TOO_LONG;
  790. }
  791. Tr("Expansion failed for %s\n", KeyName );
  792. return Error;
  793. }
  794. DWORD
  795. ReadRegistry(
  796. VOID
  797. )
  798. {
  799. HKEY hKey;
  800. DWORD Error, Size, Use351Db, DbType;
  801. CHAR Str[1024];
  802. //
  803. // Open dhcp server parameters key
  804. //
  805. Error = RegOpenKeyEx(
  806. HKEY_LOCAL_MACHINE,
  807. TEXT("SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Parameters"),
  808. 0, KEY_READ, &hKey );
  809. Tr("Open Params key failed %ld\n", Error );
  810. if( NO_ERROR != Error ) return Error;
  811. //
  812. // Read database details
  813. //
  814. do {
  815. Error = ReadString(
  816. hKey, "DatabasePath", (LPSTR)DatabasePath,
  817. sizeof(DatabasePath) );
  818. if( NO_ERROR != Error ) {
  819. Tr(" Read DatabasePath failed: %ld\n", Error );
  820. break;
  821. }
  822. Error = ReadString(
  823. hKey, "DatabaseName", (LPSTR)DatabaseName,
  824. sizeof(DatabaseName) );
  825. if( NO_ERROR != Error ) {
  826. Tr("Read DatabaseName failed %ld\n", Error );
  827. break;
  828. }
  829. strcpy(DhcpEximOemDatabaseName, DatabaseName);
  830. strcpy(DhcpEximOemDatabasePath, DatabasePath);
  831. CharToOemA(DhcpEximOemDatabaseName, DhcpEximOemDatabaseName);
  832. CharToOemA(DhcpEximOemDatabasePath, DhcpEximOemDatabasePath);
  833. if( !IsNT5() && !IsNT4() ) JetVersion = LoadJet2001;
  834. else {
  835. if( IsNT5() ) JetVersion = LoadJet97;
  836. else JetVersion = LoadJet500;
  837. Size = sizeof(DWORD);
  838. Error = RegQueryValueExA(
  839. hKey, "Use351Db", NULL, NULL, (LPBYTE)&Use351Db, &Size );
  840. if( NO_ERROR == Error ) {
  841. JetVersion = LoadJet200;
  842. } else {
  843. Size = sizeof(DWORD);
  844. Error = RegQueryValueExA(
  845. hKey, "DbType", NULL, NULL, (LPBYTE)&DbType, &Size );
  846. if( NO_ERROR == Error ) {
  847. switch(DbType) {
  848. case 3: JetVersion = LoadJet200; break;
  849. case 4: JetVersion = LoadJet500; break;
  850. }
  851. }
  852. }
  853. }
  854. Error = NO_ERROR;
  855. } while( 0 );
  856. #if DBG
  857. DbgPrint("JetVersion: %ld\n", JetVersion);
  858. #endif
  859. RegCloseKey( hKey );
  860. return Error;
  861. }
  862. DWORD
  863. InitializeDatabase(
  864. VOID
  865. )
  866. {
  867. DWORD Error;
  868. if( FALSE == SetCurrentDirectoryA(DatabasePath) ) {
  869. Error = GetLastError();
  870. if( ERROR_FILE_NOT_FOUND == Error ||
  871. ERROR_PATH_NOT_FOUND == Error ) {
  872. return ERROR_SERVICE_DOES_NOT_EXIST;
  873. }
  874. return Error;
  875. }
  876. Error = LoadAndInitializeDatabase(
  877. JetVersion, (LPSTR)DatabaseName, (LPSTR)DatabasePath );
  878. if( NO_ERROR != Error ) {
  879. Tr("LoadAndInitializeDatabase(%ld):%ld\n", JetVersion, Error );
  880. }
  881. return Error;
  882. }
  883. JET_ERR
  884. GetColumnValue(
  885. IN DWORD Index,
  886. IN LPSTR Buffer,
  887. IN OUT ULONG *BufSize
  888. )
  889. {
  890. JET_ERR Error = NO_ERROR;
  891. DWORD Size;
  892. if( ClientTable[Index].fPresent == FALSE ) {
  893. (*BufSize) = 0;
  894. return NO_ERROR;
  895. }
  896. Error = JetRetrieveColumn(
  897. JetSession, JetTbl, ClientTable[Index].ColHandle, Buffer,
  898. *BufSize, &Size, 0, NULL );
  899. if( JET_errColumnNotFound == Error ) {
  900. Error = NO_ERROR;
  901. Size = 0;
  902. }
  903. Tr("JetRetrieveColumn(%ld): %ld\n", Index, Error );
  904. if( Error < 0 ) return Error;
  905. (*BufSize) = Size;
  906. return NO_ERROR;
  907. }
  908. JET_ERR
  909. SetColumnValue(
  910. IN DWORD Index,
  911. IN LPSTR Buffer,
  912. IN ULONG BufSize
  913. )
  914. {
  915. JET_ERR Error = NO_ERROR;
  916. if( ClientTable[Index].fPresent == FALSE ) {
  917. return ERROR_CAN_NOT_COMPLETE;
  918. }
  919. Error = JetSetColumn(
  920. JetSession, JetTbl, ClientTable[Index].ColHandle, Buffer,
  921. BufSize, 0, NULL );
  922. Tr("JetSetColumn(%ld): %ld\n", Index, Error );
  923. if( Error < 0 ) return Error;
  924. return NO_ERROR;
  925. }
  926. #define CLIENT_TYPE_UNSPECIFIED 0x0 // for backward compatibility
  927. #define CLIENT_TYPE_DHCP 0x1
  928. #define CLIENT_TYPE_BOOTP 0x2
  929. #define CLIENT_TYPE_BOTH ( CLIENT_TYPE_DHCP | CLIENT_TYPE_BOOTP )
  930. #define ADDRESS_STATE_OFFERED 0
  931. #define ADDRESS_STATE_ACTIVE 1
  932. #define ADDRESS_STATE_DECLINED 2
  933. #define ADDRESS_STATE_DOOM 3
  934. #define ADDRESS_BIT_DELETED 0x80
  935. #define ADDRESS_BIT_UNREGISTERED 0x40
  936. #define ADDRESS_BIT_BOTH_REC 0x20
  937. #define ADDRESS_BIT_CLEANUP 0x10
  938. #define ADDRESS_BITS_MASK 0xF0
  939. DWORD
  940. AddRecord(
  941. IN LPSTR Buffer,
  942. IN ULONG BufSize
  943. );
  944. DWORD
  945. AddScannedClient(
  946. IN DWORD IpAddressNetOrder,
  947. IN DWORD SubnetMaskNetOrder,
  948. IN LPBYTE HwAddr,
  949. IN ULONG HwLen,
  950. IN LPWSTR MachineName,
  951. IN LPWSTR MachineInfo,
  952. IN ULONGLONG ExpirationFileTime,
  953. IN BYTE State,
  954. IN BYTE ClientType
  955. )
  956. {
  957. DWORD i;
  958. CHAR Buffer[1024];
  959. ULONG Length, Size;
  960. Length = 0;
  961. Buffer[Length++] = (BYTE)RecordTypeDbEntry;
  962. CopyMemory(
  963. &Buffer[Length], (PVOID)&IpAddressNetOrder, sizeof(DWORD) );
  964. Length += sizeof(DWORD);
  965. CopyMemory(
  966. &Buffer[Length], (PVOID)&SubnetMaskNetOrder, sizeof(DWORD) );
  967. Length += sizeof(DWORD);
  968. Buffer[Length++] = (BYTE)HwLen;
  969. CopyMemory(&Buffer[Length], HwAddr, HwLen );
  970. Length += HwLen;
  971. if( NULL == MachineName || 0 == *MachineName ) Size = 0;
  972. else Size = sizeof(WCHAR)*(1+wcslen(MachineName));
  973. CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
  974. Length += sizeof(DWORD);
  975. CopyMemory(&Buffer[Length], (PVOID)MachineName, Size );
  976. Length += Size;
  977. if( NULL == MachineInfo || 0 == *MachineInfo ) Size = 0;
  978. else Size = sizeof(WCHAR)*(1+wcslen(MachineInfo));
  979. CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
  980. Length += sizeof(DWORD);
  981. CopyMemory(&Buffer[Length], (PVOID)MachineInfo, Size );
  982. Length += Size;
  983. CopyMemory(&Buffer[Length], (PVOID)&ExpirationFileTime, sizeof(ULONGLONG));
  984. Length += sizeof(ULONGLONG);
  985. Buffer[Length++] = State;
  986. Buffer[Length++] = ClientType;
  987. return AddRecord( Buffer, Length );
  988. }
  989. BOOL
  990. SubnetNotSelected(
  991. IN ULONG Subnet,
  992. IN PULONG Subnets,
  993. IN ULONG nSubnets
  994. )
  995. {
  996. if( nSubnets == 0 ) return FALSE;
  997. while( nSubnets -- ) {
  998. if( Subnet == *Subnets++ ) return FALSE;
  999. }
  1000. return TRUE;
  1001. }
  1002. DWORD static
  1003. ScanDatabase(
  1004. IN PULONG Subnets,
  1005. IN ULONG nSubnets
  1006. )
  1007. {
  1008. LONG Error;
  1009. DWORD Count;
  1010. Error = JetSetCurrentIndex(
  1011. JetSession, JetTbl, NULL );
  1012. Tr("JetSetCurrentIndex: %ld\n", Error );
  1013. if( Error < 0 ) return Error;
  1014. Error = JetMove( JetSession, JetTbl, JET_MoveFirst, 0 );
  1015. for( Count = 0 ; Error >= 0 ; Count ++,
  1016. Error = JetMove(JetSession, JetTbl, JET_MoveNext, 0) ) {
  1017. DWORD IpAddress, SubnetMask, Size, HwLen;
  1018. FILETIME Expiration;
  1019. CHAR HwAddress[256];
  1020. WCHAR MachineName[300], MachineInfo[300];
  1021. BYTE Type, State;
  1022. //
  1023. // Get current client's info.
  1024. //
  1025. Size = sizeof(IpAddress);
  1026. Error = GetColumnValue(
  1027. IPADDRESS_INDEX, (PVOID)&IpAddress, &Size );
  1028. if( NO_ERROR != Error ) break;
  1029. if( Size != sizeof(IpAddress) ) {
  1030. Tr("Invalid Ip size\n");
  1031. continue;
  1032. }
  1033. Size = sizeof(SubnetMask);
  1034. Error = GetColumnValue(
  1035. SUBNET_MASK_INDEX, (PVOID)&SubnetMask, &Size );
  1036. if( NO_ERROR != Error ) break;
  1037. if( Size != sizeof(SubnetMask) ) {
  1038. Tr("Invalid mask size\n");
  1039. continue;
  1040. }
  1041. //
  1042. // Check if the subnet specified matches the specific
  1043. // subnet
  1044. //
  1045. if( SubnetNotSelected(
  1046. IpAddress&SubnetMask, Subnets, nSubnets ) ) {
  1047. continue;
  1048. }
  1049. HwLen = sizeof(HwAddress);
  1050. Error = GetColumnValue(
  1051. HARDWARE_ADDRESS_INDEX, (PVOID)HwAddress, &HwLen );
  1052. if( NO_ERROR != Error ) break;
  1053. Size = sizeof(MachineName);
  1054. Error = GetColumnValue(
  1055. MACHINE_NAME_INDEX, (PVOID)MachineName, &Size );
  1056. if( NO_ERROR != Error ) break;
  1057. if( (Size % 2) != 0 ) {
  1058. Tr("Invalid name size\n");
  1059. continue;
  1060. }
  1061. MachineName[Size/2] = L'\0';
  1062. Size = sizeof(MachineInfo);
  1063. Error = GetColumnValue(
  1064. MACHINE_INFO_INDEX, (PVOID)MachineInfo, &Size );
  1065. if( NO_ERROR != Error ) break;
  1066. if( (Size % 2) != 0 ) {
  1067. Tr("Invalid Info size\n");
  1068. continue;
  1069. }
  1070. MachineInfo[Size/2] = L'\0';
  1071. Size = sizeof(Expiration);
  1072. Error = GetColumnValue(
  1073. LEASE_TERMINATE_INDEX, (PVOID)&Expiration, &Size );
  1074. if( NO_ERROR != Error ) break;
  1075. if( Size != sizeof(Expiration) ) {
  1076. Tr("Invalid expiration\n");
  1077. Error = ERROR_INVALID_DATA;
  1078. break;
  1079. }
  1080. Size = sizeof(Type);
  1081. Error = GetColumnValue(
  1082. CLIENT_TYPE_INDEX, (PVOID)&Type, &Size );
  1083. if( NO_ERROR != Error || 0 == Size ) {
  1084. Type = CLIENT_TYPE_DHCP;
  1085. }
  1086. Size = sizeof(State);
  1087. Error = GetColumnValue(
  1088. STATE_INDEX, (PVOID)&State, &Size );
  1089. if( NO_ERROR != Error || 0 == Size ) {
  1090. State = ADDRESS_STATE_ACTIVE;
  1091. }
  1092. if( ADDRESS_STATE_OFFERED == State ) {
  1093. continue;
  1094. }
  1095. //
  1096. // Try to add the client
  1097. //
  1098. Error = AddScannedClient(
  1099. ByteSwap(IpAddress), ByteSwap(SubnetMask), HwAddress, HwLen,
  1100. MachineName, MachineInfo, *(PULONGLONG)&Expiration,
  1101. State, Type );
  1102. if( NO_ERROR != Error ) break;
  1103. }
  1104. Tr("Scanned %ld clients\n", Count );
  1105. if( JET_errNoCurrentRecord == Error ) return NO_ERROR;
  1106. if( Error < 0 ) return Error;
  1107. return NO_ERROR;
  1108. }
  1109. DWORD
  1110. DumpData(
  1111. IN LPSTR Buffer,
  1112. IN ULONG BufSize
  1113. )
  1114. {
  1115. return NO_ERROR;
  1116. }
  1117. DWORD
  1118. AddRecord(
  1119. IN LPSTR Buffer,
  1120. IN ULONG BufSize
  1121. )
  1122. {
  1123. DWORD Written, Error = NO_ERROR;
  1124. if( NULL != Buffer ) {
  1125. CopyMemory(&SaveBuf[SaveBufSize], (PVOID)&BufSize, sizeof(DWORD));
  1126. CopyMemory(&SaveBuf[SaveBufSize+sizeof(DWORD)], Buffer, BufSize );
  1127. } else {
  1128. if( 0 == SaveBufSize ) return NO_ERROR;
  1129. if( FALSE == WriteFile(
  1130. hTextFile, SaveBuf, SaveBufSize, &Written, NULL ) ) {
  1131. return GetLastError();
  1132. }
  1133. if( Written != SaveBufSize ) {
  1134. ASSERT(FALSE);
  1135. return ERROR_CAN_NOT_COMPLETE;
  1136. }
  1137. return NO_ERROR;
  1138. }
  1139. if( SaveBufSize <= SAVE_THRESHOLD ) {
  1140. SaveBufSize += BufSize + sizeof(DWORD);
  1141. } else {
  1142. if( FALSE == WriteFile(
  1143. hTextFile, SaveBuf, SaveBufSize + BufSize + sizeof(DWORD),
  1144. &Written, NULL )) {
  1145. return GetLastError();
  1146. }
  1147. if( Written != SaveBufSize + BufSize + sizeof(DWORD) ) {
  1148. ASSERT(FALSE);
  1149. return ERROR_CAN_NOT_COMPLETE;
  1150. }
  1151. SaveBufSize = 0;
  1152. }
  1153. return Error;
  1154. }
  1155. DWORD
  1156. AddRecordNoSize(
  1157. IN LPSTR Buffer,
  1158. IN ULONG BufSize
  1159. )
  1160. {
  1161. DWORD Written, Error = NO_ERROR;
  1162. if( NULL != Buffer ) {
  1163. CopyMemory(&SaveBuf[SaveBufSize], Buffer, BufSize );
  1164. } else {
  1165. if( 0 == SaveBufSize ) return NO_ERROR;
  1166. if( FALSE == WriteFile(
  1167. hTextFile, SaveBuf, SaveBufSize, &Written, NULL ) ) {
  1168. return GetLastError();
  1169. }
  1170. if( Written != SaveBufSize ) {
  1171. ASSERT(FALSE);
  1172. return ERROR_CAN_NOT_COMPLETE;
  1173. }
  1174. return NO_ERROR;
  1175. }
  1176. if( SaveBufSize <= SAVE_THRESHOLD ) {
  1177. SaveBufSize += BufSize;
  1178. } else {
  1179. if( FALSE == WriteFile(
  1180. hTextFile, SaveBuf, SaveBufSize + BufSize,
  1181. &Written, NULL )) {
  1182. return GetLastError();
  1183. }
  1184. if( Written != SaveBufSize + BufSize ) {
  1185. ASSERT(FALSE);
  1186. return ERROR_CAN_NOT_COMPLETE;
  1187. }
  1188. SaveBufSize = 0;
  1189. }
  1190. return Error;
  1191. }
  1192. DWORD
  1193. StopDhcpService(
  1194. VOID
  1195. )
  1196. {
  1197. SC_HANDLE hSc, hSvc;
  1198. DWORD Error;
  1199. Error = NO_ERROR;
  1200. hSc = NULL;
  1201. hSvc = NULL;
  1202. do {
  1203. hSc = OpenSCManager(
  1204. NULL, NULL, SC_MANAGER_CONNECT | GENERIC_READ | GENERIC_WRITE );
  1205. if( NULL == hSc ) {
  1206. Error = GetLastError();
  1207. Tr("OpenSCManager: %ld\n", Error );
  1208. break;
  1209. }
  1210. hSvc = OpenService(
  1211. hSc, TEXT("DHCPServer"), SERVICE_STOP| SERVICE_QUERY_STATUS );
  1212. if( NULL == hSvc ) {
  1213. Error = GetLastError();
  1214. Tr("OpenService: %ld\n", Error );
  1215. break;
  1216. }
  1217. while( NO_ERROR == Error ) {
  1218. SERVICE_STATUS Status;
  1219. if( FALSE == QueryServiceStatus( hSvc, &Status ) ) {
  1220. Error = GetLastError();
  1221. Tr( "QueryServiceStatus: %ld\n", Error );
  1222. break;
  1223. }
  1224. if( Status.dwCurrentState == SERVICE_STOPPED ) break;
  1225. if( Status.dwCurrentState != SERVICE_RUNNING &&
  1226. Status.dwCurrentState != SERVICE_PAUSED ) {
  1227. Tr( "Waiting, state = %ld\n", Status.dwCurrentState );
  1228. if( Status.dwWaitHint < 1000 ) {
  1229. Status.dwWaitHint = 1000;
  1230. }
  1231. if( Status.dwWaitHint > 5000 ) {
  1232. Status.dwWaitHint = 1000;
  1233. }
  1234. Sleep(Status.dwWaitHint);
  1235. } else {
  1236. Error = ControlService(
  1237. hSvc, SERVICE_CONTROL_STOP, &Status );
  1238. if( FALSE != Error ) Error = NO_ERROR;
  1239. else {
  1240. Error = GetLastError();
  1241. Tr("ControlService: %ld\n", Error );
  1242. break;
  1243. }
  1244. }
  1245. }
  1246. } while( 0 );
  1247. if( NULL != hSvc ) CloseServiceHandle( hSvc );
  1248. if( NULL != hSc ) CloseServiceHandle( hSc );
  1249. return Error;
  1250. }
  1251. DWORD
  1252. StartDhcpService(
  1253. VOID
  1254. )
  1255. {
  1256. SC_HANDLE hSc, hSvc;
  1257. DWORD Error;
  1258. Error = NO_ERROR;
  1259. hSc = NULL;
  1260. hSvc = NULL;
  1261. do {
  1262. hSc = OpenSCManager(
  1263. NULL, NULL, SC_MANAGER_CONNECT | GENERIC_READ | GENERIC_WRITE );
  1264. if( NULL == hSc ) {
  1265. Error = GetLastError();
  1266. Tr("OpenSCManager: %ld\n", Error );
  1267. break;
  1268. }
  1269. hSvc = OpenService(
  1270. hSc, TEXT("DHCPServer"), SERVICE_START| SERVICE_QUERY_STATUS );
  1271. if( NULL == hSvc ) {
  1272. Error = GetLastError();
  1273. Tr("OpenService: %ld\n", Error );
  1274. break;
  1275. }
  1276. Error = StartService( hSvc, 0, NULL );
  1277. if( FALSE == Error ) Error = GetLastError(); else Error = NO_ERROR;
  1278. if( NO_ERROR != Error ) break;
  1279. while( NO_ERROR == Error ) {
  1280. SERVICE_STATUS Status;
  1281. if( FALSE == QueryServiceStatus( hSvc, &Status ) ) {
  1282. Error = GetLastError();
  1283. Tr("QueryServiceStatus: %ld\n", Error );
  1284. break;
  1285. }
  1286. if( Status.dwCurrentState == SERVICE_RUNNING ) break;
  1287. if( Status.dwCurrentState == SERVICE_START_PENDING ) {
  1288. Tr("Sleeping %ld\n", Status.dwWaitHint );
  1289. if( Status.dwWaitHint < 1000 ) {
  1290. Status.dwWaitHint = 1000;
  1291. }
  1292. if( Status.dwWaitHint > 5000 ) {
  1293. Status.dwWaitHint = 5000;
  1294. }
  1295. Sleep(Status.dwWaitHint);
  1296. } else {
  1297. Error = ERROR_CAN_NOT_COMPLETE;
  1298. break;
  1299. }
  1300. }
  1301. } while( 0 );
  1302. if( NULL != hSvc ) CloseServiceHandle( hSvc );
  1303. if( NULL != hSc ) CloseServiceHandle( hSc );
  1304. return Error;
  1305. }
  1306. DWORD __stdcall PrintRecord(
  1307. IN PDHCP_RECORD Recx
  1308. )
  1309. {
  1310. DWORD i;
  1311. DHCP_RECORD Rec = *Recx;
  1312. if( Rec.fMcast ) {
  1313. printf("Mcast Record\n" );
  1314. printf("Address: %s\n", IpAddressToString(
  1315. Rec.Info.Mcast.Address ));
  1316. printf("ScopeId: %s\n", IpAddressToString(
  1317. Rec.Info.Mcast.ScopeId ));
  1318. printf("ClientId:");
  1319. for( i = 0 ; i < (DWORD)Rec.Info.Mcast.HwLen; i ++ ) {
  1320. printf(" %02X", Rec.Info.Mcast.ClientId[i]);
  1321. }
  1322. printf("\nState = %02X\n", Rec.Info.Mcast.State);
  1323. } else {
  1324. printf("DHCP Record\n" );
  1325. printf("Address: %s\n", IpAddressToString(
  1326. Rec.Info.Dhcp.Address ));
  1327. printf("Mask: %s\n", IpAddressToString(
  1328. Rec.Info.Dhcp.Mask ));
  1329. printf("ClientId:");
  1330. for( i = 0 ; i < (DWORD)Rec.Info.Dhcp.HwLen; i ++ ) {
  1331. printf(" %02X", Rec.Info.Dhcp.HwAddr[i]);
  1332. }
  1333. printf("\nState = %02X\n", Rec.Info.Dhcp.State);
  1334. printf("\nType = %02X\n", Rec.Info.Dhcp.Type);
  1335. if( Rec.Info.Dhcp.Name ) {
  1336. printf("Name = %ws\n", Rec.Info.Dhcp.Name );
  1337. }
  1338. if( Rec.Info.Dhcp.Info ) {
  1339. printf("Comment = %ws\n", Rec.Info.Dhcp.Info );
  1340. }
  1341. }
  1342. return NO_ERROR;
  1343. }
  1344. DWORD
  1345. StringLen(
  1346. IN WCHAR UNALIGNED *Str
  1347. )
  1348. {
  1349. DWORD Size = sizeof(WCHAR);
  1350. if( NULL == Str ) return 0;
  1351. while( *Str ++ != L'\0' ) Size += sizeof(WCHAR);
  1352. return Size;
  1353. }
  1354. DWORD __stdcall
  1355. AddRecordToDatabase(
  1356. IN PDHCP_RECORD Recx
  1357. )
  1358. {
  1359. DWORD Index;
  1360. JET_ERR Error;
  1361. DHCP_RECORD Rec = *Recx;
  1362. WCHAR Address[30], HwAddress[300];
  1363. IpAddressToStringW(Rec.Info.Dhcp.Address, Address);
  1364. DhcpHexToString(
  1365. HwAddress, Rec.Info.Dhcp.HwAddr,
  1366. Rec.Info.Dhcp.HwLen );
  1367. Error = JetBeginTransaction( JetSession );
  1368. Tr( "JetBeginTransaction: %ld\n", Error );
  1369. if( Error < 0 ) return Error;
  1370. do {
  1371. Error = JetPrepareUpdate( JetSession, JetTbl, JET_prepInsert );
  1372. if( Error ) Tr( "JetPrepareUpdate: %ld\n", Error );
  1373. if( Error < 0 ) break;
  1374. Index = IPADDRESS_INDEX;
  1375. Error = SetColumnValue(
  1376. Index, (LPBYTE)&Rec.Info.Dhcp.Address, sizeof(DWORD) );
  1377. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1378. if( Error < 0 ) break;
  1379. Index = SUBNET_MASK_INDEX;
  1380. Error = SetColumnValue(
  1381. Index, (LPBYTE)&Rec.Info.Dhcp.Mask, sizeof(DWORD) );
  1382. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1383. if( Error < 0 ) break;
  1384. Index = HARDWARE_ADDRESS_INDEX;
  1385. Error = SetColumnValue(
  1386. Index, Rec.Info.Dhcp.HwAddr, Rec.Info.Dhcp.HwLen );
  1387. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1388. if( Error < 0 ) break;
  1389. Index = STATE_INDEX;
  1390. Error = SetColumnValue(
  1391. Index, &Rec.Info.Dhcp.State, sizeof(BYTE) );
  1392. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1393. if( Error < 0 ) break;
  1394. Index = CLIENT_TYPE_INDEX;
  1395. Error = SetColumnValue(
  1396. Index, &Rec.Info.Dhcp.Type, sizeof(BYTE) );
  1397. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1398. if( Error < 0 ) break;
  1399. Index = MACHINE_INFO_INDEX;
  1400. Error = SetColumnValue(
  1401. Index, (LPBYTE)Rec.Info.Dhcp.Info, StringLen(Rec.Info.Dhcp.Info) );
  1402. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1403. if( Error < 0 ) break;
  1404. Index = MACHINE_NAME_INDEX;
  1405. Error = SetColumnValue(
  1406. Index, (LPBYTE)Rec.Info.Dhcp.Name, StringLen(Rec.Info.Dhcp.Name) );
  1407. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1408. if( Error < 0 ) break;
  1409. Index = LEASE_TERMINATE_INDEX;
  1410. Error = SetColumnValue(
  1411. Index, (LPBYTE)&Rec.Info.Dhcp.ExpTime, sizeof(FILETIME) );
  1412. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1413. if( Error < 0 ) break;
  1414. Index = SERVER_IP_ADDRESS_INDEX;
  1415. Rec.Info.Dhcp.Address = INADDR_LOOPBACK;
  1416. Error = SetColumnValue(
  1417. Index, (LPBYTE)&Rec.Info.Dhcp.Address, sizeof(DWORD));
  1418. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1419. if( Error < 0 ) break;
  1420. Index = SERVER_NAME_INDEX;
  1421. Rec.Info.Dhcp.Name = L"";
  1422. Error = SetColumnValue(
  1423. Index, (LPBYTE)Rec.Info.Dhcp.Name, StringLen(Rec.Info.Dhcp.Name));
  1424. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1425. if( Error < 0 ) break;
  1426. Error = JetUpdate( JetSession, JetTbl, NULL, 0, NULL );
  1427. if( Error ) Tr( "JetUpdate: %ld\n", Error );
  1428. if( Error < 0 ) break;
  1429. } while ( 0 );
  1430. if( Error < 0 ) {
  1431. BOOL fAbort;
  1432. JetRollback( JetSession, 0 );
  1433. fAbort = TRUE;
  1434. DhcpEximErrorDatabaseEntryFailed(
  1435. Address, HwAddress, Error, &fAbort );
  1436. if( fAbort ) return ERROR_CAN_NOT_COMPLETE;
  1437. } else {
  1438. JetCommitTransaction( JetSession, 0 );
  1439. }
  1440. return NO_ERROR;
  1441. }
  1442. DWORD
  1443. ProcessDbEntries(
  1444. IN LPSTR Buffer,
  1445. IN ULONG BufSize,
  1446. IN PULONG Subnets,
  1447. IN ULONG nSubnets,
  1448. IN DHCP_ADD_RECORD_ROUTINE AddRec
  1449. )
  1450. {
  1451. DWORD Size, ThisSize, DbEntry;
  1452. LPSTR Buf;
  1453. DWORD Address, i, Error;
  1454. FILETIME Time;
  1455. DHCP_RECORD Rec;
  1456. Error = NO_ERROR;
  1457. while( BufSize > sizeof(DWORD) ) {
  1458. CopyMemory(&ThisSize, Buffer, sizeof(DWORD));
  1459. Buffer += sizeof(DWORD);
  1460. BufSize -= sizeof(DWORD);
  1461. if( ThisSize > BufSize ) return ERROR_INVALID_DATA;
  1462. if( ThisSize == 0 ) continue;
  1463. DbEntry = *Buffer;
  1464. Buf = Buffer+1;
  1465. Buffer += ThisSize;
  1466. BufSize -= ThisSize;
  1467. ZeroMemory( &Rec, sizeof(Rec));
  1468. switch(DbEntry) {
  1469. default :
  1470. return ERROR_INVALID_DATA;
  1471. case RecordTypeDbEntry :
  1472. Rec.fMcast = FALSE;
  1473. CopyMemory( &Rec.Info.Dhcp.Address, Buf, sizeof(DWORD));
  1474. Rec.Info.Dhcp.Address = ByteSwap(Rec.Info.Dhcp.Address);
  1475. Buf += sizeof(DWORD);
  1476. CopyMemory( &Rec.Info.Dhcp.Mask, Buf, sizeof(DWORD));
  1477. Rec.Info.Dhcp.Mask = ByteSwap(Rec.Info.Dhcp.Mask);
  1478. Buf += sizeof(DWORD);
  1479. Size = Rec.Info.Dhcp.HwLen = *Buf++;
  1480. Rec.Info.Dhcp.HwAddr = Buf;
  1481. Buf += Size;
  1482. CopyMemory(&Size, Buf, sizeof(DWORD));
  1483. Buf += sizeof(DWORD);
  1484. if( Size ) {
  1485. Rec.Info.Dhcp.Name = (PVOID)Buf;
  1486. Buf += Size;
  1487. }
  1488. CopyMemory(&Size, Buf, sizeof(DWORD));
  1489. Buf += sizeof(DWORD);
  1490. if( Size ) {
  1491. Rec.Info.Dhcp.Info = (PVOID)Buf;
  1492. Buf += Size;
  1493. }
  1494. CopyMemory(&Rec.Info.Dhcp.ExpTime, Buf, sizeof(FILETIME));
  1495. Buf += sizeof(FILETIME);
  1496. Rec.Info.Dhcp.State = Buf[0];
  1497. Rec.Info.Dhcp.Type = Buf[1];
  1498. //
  1499. // Add the subnet only if it is selected
  1500. //
  1501. if( !SubnetNotSelected(
  1502. Rec.Info.Dhcp.Address & Rec.Info.Dhcp.Mask,
  1503. Subnets, nSubnets ) ) {
  1504. Error = AddRec( &Rec );
  1505. }
  1506. break;
  1507. case RecordTypeMcastDbEntry :
  1508. Rec.fMcast = TRUE;
  1509. CopyMemory( &Rec.Info.Mcast.Address, Buf, sizeof(DWORD));
  1510. Buf += sizeof(DWORD);
  1511. CopyMemory( &Rec.Info.Mcast.ScopeId, Buf, sizeof(DWORD));
  1512. Buf += sizeof(DWORD);
  1513. Size = Rec.Info.Mcast.HwLen = *Buf++;
  1514. Rec.Info.Mcast.ClientId = Buf;
  1515. Buf += Size;
  1516. CopyMemory(&Size, Buf, sizeof(DWORD));
  1517. Buf += sizeof(DWORD);
  1518. if( Size ) {
  1519. Rec.Info.Mcast.Info = (PVOID)Buf;
  1520. Buf += Size;
  1521. }
  1522. CopyMemory(&Rec.Info.Mcast.End, Buf, sizeof(FILETIME));
  1523. Buf += sizeof(FILETIME);
  1524. CopyMemory(&Rec.Info.Mcast.Start, Buf, sizeof(FILETIME));
  1525. Buf += sizeof(FILETIME);
  1526. Rec.Info.Mcast.State = Buf[0];
  1527. Error = AddRec( &Rec );
  1528. break;
  1529. }
  1530. if( NO_ERROR != Error ) return Error;
  1531. }
  1532. return NO_ERROR;
  1533. }
  1534. DWORD
  1535. SaveDatabaseEntriesToFile(
  1536. IN PULONG Subnets,
  1537. IN ULONG nSubnets
  1538. )
  1539. {
  1540. DWORD Error;
  1541. Error = InitializeDatabase();
  1542. if( NO_ERROR != Error ) {
  1543. Tr("InitializeDatabase: %ld\n", Error );
  1544. return Error;
  1545. }
  1546. Error = ScanDatabase(Subnets, nSubnets);
  1547. if( NO_ERROR != Error ) {
  1548. Tr("ScanDatabase: %ld\n", Error);
  1549. } else {
  1550. AddRecord( NULL, 0 );
  1551. }
  1552. CleanupDatabase();
  1553. return Error;
  1554. }
  1555. DWORD
  1556. SaveFileEntriesToDatabase(
  1557. IN LPBYTE Mem,
  1558. IN ULONG MemSize,
  1559. IN PULONG Subnets,
  1560. IN ULONG nSubnets
  1561. )
  1562. {
  1563. DWORD Error;
  1564. Error = InitializeDatabase();
  1565. if( NO_ERROR != Error ) {
  1566. Tr("InitializeDatabase: %ld\n", Error );
  1567. return Error;
  1568. }
  1569. Error = ProcessDbEntries(
  1570. Mem, MemSize, Subnets, nSubnets, AddRecordToDatabase );
  1571. if( NO_ERROR != Error ) {
  1572. Tr("ProcessDbEntries: %ld\n", Error );
  1573. }
  1574. CleanupDatabase();
  1575. return Error;
  1576. }
  1577. DWORD
  1578. InitializeDatabaseParameters(
  1579. VOID
  1580. )
  1581. {
  1582. DWORD Error;
  1583. //
  1584. // Stop the service
  1585. //
  1586. Error = StopDhcpService();
  1587. if( NO_ERROR != Error ) {
  1588. Tr("StopDhcpService: %ld\n", Error );
  1589. return Error;
  1590. }
  1591. //
  1592. // Read the registry and otherwise initialize the database
  1593. // parameters, without actually opening the database.
  1594. //
  1595. Error = ReadRegistry();
  1596. Tr("ReadRegistry: %ld\n", Error );
  1597. if( NO_ERROR != Error ) return Error;
  1598. Error = ConvertPermissionsOnDbFiles();
  1599. Tr("ConvertPermissionsOnDbFiles: %ld\n", Error );
  1600. // ignore error and try best effort
  1601. if( FALSE == SetCurrentDirectoryA(DatabasePath) ) {
  1602. Error = GetLastError();
  1603. if( ERROR_FILE_NOT_FOUND == Error ||
  1604. ERROR_PATH_NOT_FOUND == Error ) {
  1605. return ERROR_SERVICE_DOES_NOT_EXIST;
  1606. }
  1607. return Error;
  1608. }
  1609. return NO_ERROR;
  1610. }
  1611. DWORD
  1612. CleanupDatabaseParameters(
  1613. VOID
  1614. )
  1615. {
  1616. DWORD Error;
  1617. Error = StartDhcpService();
  1618. if( NO_ERROR != Error ) {
  1619. Tr("StartDhcpService: %ld\n", Error );
  1620. }
  1621. return Error;
  1622. }