Leaked source code of windows server 2003
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.

2027 lines
52 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_coltypLongBinary },
  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_coltypLongBinary },
  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. memcpy( Temp, DbPath,
  490. (( sizeof( Temp ) - 1 ) < strlen( DbPath ))
  491. ? sizeof( Temp ) : strlen( DbPath ) + 1 );
  492. Temp[ sizeof( Temp ) - 2 ] = '\0';
  493. if( LoadJet200 == JetVersion ) {
  494. strcat(Temp, DbSysFile);
  495. JetParam = JET_paramSysDbPath_OLD;
  496. } else {
  497. strcat(Temp, "\\");
  498. if( LoadJet97 > JetVersion ) {
  499. JetParam = JET_paramSystemPath_OLD;
  500. } else {
  501. JetParam = JET_paramSystemPath;
  502. }
  503. }
  504. Error = JetSetSystemParameter(
  505. &JetInstance, (JET_SESID)0, JetParam, 0, Temp );
  506. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  507. if( NO_ERROR != Error ) return Error;
  508. if( LoadJet200 != JetVersion ) {
  509. if( LoadJet97 > JetVersion ) {
  510. JetParam = JET_paramBaseName_OLD;
  511. } else {
  512. JetParam = JET_paramBaseName;
  513. }
  514. Error = JetSetSystemParameter(
  515. &JetInstance, (JET_SESID)0, JetParam, 0, DbBaseName );
  516. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  517. if( NO_ERROR != Error ) return Error;
  518. }
  519. if( LoadJet200 != JetVersion ) {
  520. if( LoadJet97 <= JetVersion ) {
  521. JetParam = JET_paramLogFileSize;
  522. } else {
  523. JetParam = JET_paramLogFileSize_OLD;
  524. }
  525. Error = JetSetSystemParameter(
  526. &JetInstance, (JET_SESID)0, JetParam, LogFileSize, NULL );
  527. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  528. if( NO_ERROR != Error ) return Error;
  529. }
  530. if( LoadJet200 != JetVersion ) {
  531. Error = JetSetSystemParameter(
  532. &JetInstance, (JET_SESID)0,
  533. JET_paramCheckFormatWhenOpenFail, 1, NULL );
  534. JetParam = JET_paramCheckFormatWhenOpenFail;
  535. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  536. if( NO_ERROR != Error ) return Error;
  537. }
  538. if( LoadJet200 != JetVersion ) {
  539. if( LoadJet97 > JetVersion ) {
  540. JetParam = JET_paramRecovery_OLD;
  541. } else {
  542. JetParam = JET_paramRecovery;
  543. }
  544. Error = JetSetSystemParameter(
  545. &JetInstance, (JET_SESID)0, JetParam, 0, "on");
  546. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  547. if( NO_ERROR != Error ) return Error;
  548. }
  549. //
  550. // Note: Ideally, the log files should never exist. Even
  551. // if the database is opened in readonly mode, they seem to
  552. // exist. Not sure what else can be done
  553. //
  554. if( LoadJet97 <= JetVersion ) {
  555. JetParam = JET_paramLogFilePath;
  556. } else {
  557. JetParam = JET_paramLogFilePath_OLD;
  558. }
  559. strcpy(Temp, DbPath); strcat( Temp, "\\");
  560. Error = JetSetSystemParameter(
  561. &JetInstance, (JET_SESID)0, JetParam, 0, Temp );
  562. Tr("SetDbParam %ld: %ld\n", JetParam, Error );
  563. return Error;
  564. }
  565. DWORD
  566. OpenDatabase(
  567. IN DWORD JetVersion,
  568. IN LPSTR DbName,
  569. IN LPSTR DbPath
  570. )
  571. {
  572. LONG Error;
  573. DWORD i;
  574. CHAR FilePath[2048];
  575. JET_INDEXLIST TmpIdxList;
  576. DWORD Len, Len1;
  577. JetSession = 0;
  578. JetDb = 0;
  579. JetTbl = 0;
  580. Error = JetInit( &JetInstance );
  581. Tr("JetInit: %ld\n", Error );
  582. if( NO_ERROR != Error ) return Error;
  583. Error = JetBeginSession(
  584. JetInstance, &JetSession, "admin", "" );
  585. Tr("JetBeginSession: %ld\n", Error);
  586. if( Error < 0 ) return Error;
  587. Error = JetDetachDatabase( JetSession, NULL );
  588. Tr("JetDetachDatabase:%ld\n", Error );
  589. if( Error < 0 ) return Error;
  590. // Create the filename
  591. Len = strlen( DbName );
  592. Len1 = strlen( DbPath );
  593. if ( sizeof( FilePath ) < ( Len + Len1 + 2 )) { // 2 for '\\' and '\0'
  594. return ERROR_INVALID_PARAMETER;
  595. }
  596. memcpy( FilePath, DbPath, Len1 );
  597. FilePath[ Len1 ] = '\\';
  598. memcpy( FilePath + Len1 + 1, DbName, Len );
  599. FilePath[ Len + Len1 + 1 ] = '\0';
  600. Error = JetAttachDatabase( JetSession, FilePath, JET_bitDbExclusive );
  601. Tr("JetAttachDatabase:%ld\n", Error );
  602. if( Error < 0 ) return Error;
  603. Error = JetOpenDatabase(
  604. JetSession, FilePath, NULL, &JetDb,
  605. JET_bitDbSingleExclusive );
  606. Tr("JetOpenDatabase: %ld\n", Error);
  607. if( Error < 0 ) return Error;
  608. Error = JetOpenTable(
  609. JetSession, JetDb, (LPSTR)"ClientTable",
  610. NULL, 0, 0,&JetTbl );
  611. Tr("JetOpenTable: %ld\n", Error );
  612. if( Error < 0 ) return Error;
  613. for( i = 0; i < sizeof(ClientTable)/sizeof(ClientTable[0]); i ++ ) {
  614. JET_COLUMNDEF ColDef;
  615. Error = JetGetTableColumnInfo(
  616. JetSession, JetTbl, ClientTable[i].ColName, &ColDef,
  617. sizeof(ColDef), 0 );
  618. if(Error && JET_errColumnNotFound != Error ) {
  619. Tr("JetGetCol: %ld\n", Error );
  620. }
  621. if( Error < 0 ) {
  622. if( JET_errColumnNotFound == Error ) {
  623. ClientTable[i].fPresent = FALSE;
  624. continue;
  625. } else {
  626. return Error;
  627. }
  628. }
  629. if( ColDef.coltyp != ClientTable[i].ColType ) {
  630. ASSERT( FALSE );
  631. Error = ERROR_BAD_FORMAT;
  632. return Error;
  633. }
  634. ClientTable[i].ColHandle = ColDef.columnid;
  635. }
  636. return NO_ERROR;
  637. }
  638. DWORD
  639. LoadAndInitializeDatabase(
  640. IN DWORD JetVersion,
  641. IN LPSTR DbName,
  642. IN LPSTR DbPath
  643. )
  644. {
  645. DWORD Error;
  646. //
  647. // Attempt to load DLL and retrieve function pointers
  648. //
  649. Tr("Loading %ld jet version\n", JetVersion );
  650. Error = LoadAndLinkRoutines( JetVersion );
  651. if( NO_ERROR != Error ) return Error;
  652. //
  653. // set standard jet params
  654. //
  655. Error = SetJetParams( JetVersion, DbName, DbPath );
  656. if( NO_ERROR != Error ) {
  657. FreeLibrary( hJet ); hJet = NULL;
  658. return Error;
  659. }
  660. //
  661. // Attempt to open database
  662. //
  663. Error = OpenDatabase( JetVersion, DbName, DbPath );
  664. if( NO_ERROR != Error ) {
  665. CleanupDatabase();
  666. return Error;
  667. }
  668. return NO_ERROR;
  669. }
  670. DWORD
  671. LoadAndLinkSecurityRoutines(
  672. OUT FARPROC *pGetInfo,
  673. OUT FARPROC *pSetInfo
  674. )
  675. {
  676. HMODULE hAdvapi32;
  677. hAdvapi32 = GetModuleHandle(TEXT("ADVAPI32.DLL"));
  678. if( NULL == hAdvapi32 ) return GetLastError();
  679. (*pGetInfo) = GetProcAddress(hAdvapi32, "GetNamedSecurityInfoA");
  680. if( NULL == *pGetInfo ) return GetLastError();
  681. (*pSetInfo) = GetProcAddress(hAdvapi32, "SetNamedSecurityInfoA");
  682. if( NULL == *pSetInfo ) return GetLastError();
  683. return NO_ERROR;
  684. }
  685. DWORD
  686. ConvertPermissionsOnDbFiles(
  687. VOID
  688. )
  689. {
  690. DWORD Error, dwVersion = GetVersion();
  691. PSECURITY_DESCRIPTOR pSec;
  692. PACL pAcl;
  693. HANDLE hSearch = INVALID_HANDLE_VALUE;
  694. WIN32_FIND_DATAA FileData;
  695. CHAR FileName[1024];
  696. FARPROC pGetInfo, pSetInfo;
  697. CHAR DriversDirPath[MAX_PATH *2 +1];
  698. DWORD PathLen = sizeof(DriversDirPath)-1;
  699. //
  700. // Check if version is atleast NT5.
  701. //
  702. dwVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
  703. if( dwVersion < 5 ) return NO_ERROR;
  704. //
  705. // First get the requried function pointers..
  706. //
  707. Error = LoadAndLinkSecurityRoutines(
  708. &pGetInfo, &pSetInfo );
  709. if( NO_ERROR != Error ) return Error;
  710. ZeroMemory(DriversDirPath, PathLen+1);
  711. PathLen = ExpandEnvironmentStringsA(
  712. "%SystemRoot%\\system32\\drivers", DriversDirPath, PathLen );
  713. if( PathLen == 0 ) {
  714. Error = GetLastError();
  715. return Error;
  716. }
  717. pSec = NULL;
  718. pAcl = NULL;
  719. Error = (DWORD)pGetInfo(
  720. DriversDirPath, //"MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer",
  721. SE_FILE_OBJECT, // SE_REGISTRY_KEY
  722. DACL_SECURITY_INFORMATION, NULL, NULL,
  723. &pAcl, NULL, &pSec );
  724. if( NO_ERROR != Error ) return Error;
  725. Error = (DWORD)pSetInfo(
  726. DatabasePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
  727. NULL, NULL, pAcl, NULL );
  728. if( NO_ERROR != Error ) return Error;
  729. strcpy(FileName, DatabasePath);
  730. if( FileName[strlen(FileName)-1] != '\\' ) {
  731. strcat(FileName, "\\");
  732. }
  733. strcat(FileName, DatabaseName);
  734. Error = (DWORD)pSetInfo(
  735. FileName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
  736. NULL, NULL, pAcl, NULL );
  737. if( NO_ERROR != Error ) goto Cleanup;
  738. //
  739. // Now for all files matching "*.log", repeat above operation
  740. //
  741. strcpy(FileName, DatabasePath);
  742. if( FileName[strlen(FileName)-1] != '\\' ) {
  743. strcat(FileName, "\\");
  744. }
  745. strcat(FileName, "*.*");
  746. hSearch = FindFirstFileA( FileName, &FileData );
  747. if( INVALID_HANDLE_VALUE == hSearch ) {
  748. Error = GetLastError();
  749. goto Cleanup;
  750. }
  751. do {
  752. if( 0 != strcmp(FileData.cFileName, ".") &&
  753. 0 != strcmp(FileData.cFileName, "..") ) {
  754. strcpy(FileName, DatabasePath);
  755. if( FileName[strlen(FileName)-1] != '\\' ) {
  756. strcat(FileName, "\\");
  757. }
  758. strcat(FileName, FileData.cFileName);
  759. Error = (DWORD)pSetInfo(
  760. FileName, SE_FILE_OBJECT,
  761. DACL_SECURITY_INFORMATION, NULL, NULL, pAcl, NULL );
  762. if( NO_ERROR != Error ) break;
  763. }
  764. Error = FindNextFileA( hSearch, &FileData );
  765. if( FALSE != Error ) Error = NO_ERROR;
  766. else Error = GetLastError();
  767. } while( NO_ERROR == Error );
  768. FindClose( hSearch );
  769. Cleanup:
  770. LocalFree( pSec );
  771. if( ERROR_FILE_NOT_FOUND == Error ) return NO_ERROR;
  772. if( ERROR_NO_MORE_FILES == Error ) return NO_ERROR;
  773. return Error;
  774. }
  775. DWORD
  776. ReadString(
  777. IN HKEY hKey,
  778. IN LPSTR KeyName,
  779. IN LPSTR Buffer,
  780. IN ULONG BufSize
  781. )
  782. {
  783. DWORD Error, Size, Type;
  784. CHAR Str[1024];
  785. Size = sizeof(Str);
  786. Error = RegQueryValueExA(
  787. hKey, KeyName, NULL, &Type, (LPSTR)Str, &Size );
  788. if( NO_ERROR == Error ) {
  789. if( 0 == Size || 1 == Size ) Error = ERROR_NOT_FOUND;
  790. if( Type != REG_SZ && Type != REG_EXPAND_SZ && Type !=
  791. REG_MULTI_SZ ) Error = ERROR_BAD_FORMAT;
  792. }
  793. if( NO_ERROR != Error ) return Error;
  794. Size = ExpandEnvironmentStringsA( (LPSTR)Str, Buffer, BufSize );
  795. if( Size == 0 || Size > BufSize ) {
  796. Error = ERROR_META_EXPANSION_TOO_LONG;
  797. }
  798. Tr("Expansion failed for %s\n", KeyName );
  799. return Error;
  800. }
  801. DWORD
  802. ReadRegistry(
  803. VOID
  804. )
  805. {
  806. HKEY hKey;
  807. DWORD Error, Size, Use351Db, DbType;
  808. CHAR Str[1024];
  809. //
  810. // Open dhcp server parameters key
  811. //
  812. Error = RegOpenKeyEx(
  813. HKEY_LOCAL_MACHINE,
  814. TEXT("SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Parameters"),
  815. 0, KEY_READ, &hKey );
  816. Tr("Open Params key failed %ld\n", Error );
  817. if( NO_ERROR != Error ) return Error;
  818. //
  819. // Read database details
  820. //
  821. do {
  822. Error = ReadString(
  823. hKey, "DatabasePath", (LPSTR)DatabasePath,
  824. sizeof(DatabasePath) );
  825. if( NO_ERROR != Error ) {
  826. Tr(" Read DatabasePath failed: %ld\n", Error );
  827. break;
  828. }
  829. Error = ReadString(
  830. hKey, "DatabaseName", (LPSTR)DatabaseName,
  831. sizeof(DatabaseName) );
  832. if( NO_ERROR != Error ) {
  833. Tr("Read DatabaseName failed %ld\n", Error );
  834. break;
  835. }
  836. strcpy(DhcpEximOemDatabaseName, DatabaseName);
  837. strcpy(DhcpEximOemDatabasePath, DatabasePath);
  838. CharToOemA(DhcpEximOemDatabaseName, DhcpEximOemDatabaseName);
  839. CharToOemA(DhcpEximOemDatabasePath, DhcpEximOemDatabasePath);
  840. if( !IsNT5() && !IsNT4() ) JetVersion = LoadJet2001;
  841. else {
  842. if( IsNT5() ) JetVersion = LoadJet97;
  843. else JetVersion = LoadJet500;
  844. Size = sizeof(DWORD);
  845. Error = RegQueryValueExA(
  846. hKey, "Use351Db", NULL, NULL, (LPBYTE)&Use351Db, &Size );
  847. if( NO_ERROR == Error ) {
  848. JetVersion = LoadJet200;
  849. } else {
  850. Size = sizeof(DWORD);
  851. Error = RegQueryValueExA(
  852. hKey, "DbType", NULL, NULL, (LPBYTE)&DbType, &Size );
  853. if( NO_ERROR == Error ) {
  854. switch(DbType) {
  855. case 3: JetVersion = LoadJet200; break;
  856. case 4: JetVersion = LoadJet500; break;
  857. }
  858. }
  859. }
  860. }
  861. Error = NO_ERROR;
  862. } while( 0 );
  863. #if DBG
  864. DbgPrint("JetVersion: %ld\n", JetVersion);
  865. #endif
  866. RegCloseKey( hKey );
  867. return Error;
  868. }
  869. DWORD
  870. InitializeDatabase(
  871. VOID
  872. )
  873. {
  874. DWORD Error;
  875. if( FALSE == SetCurrentDirectoryA(DatabasePath) ) {
  876. Error = GetLastError();
  877. if( ERROR_FILE_NOT_FOUND == Error ||
  878. ERROR_PATH_NOT_FOUND == Error ) {
  879. return ERROR_SERVICE_DOES_NOT_EXIST;
  880. }
  881. return Error;
  882. }
  883. Error = LoadAndInitializeDatabase(
  884. JetVersion, (LPSTR)DatabaseName, (LPSTR)DatabasePath );
  885. if( NO_ERROR != Error ) {
  886. Tr("LoadAndInitializeDatabase(%ld):%ld\n", JetVersion, Error );
  887. }
  888. return Error;
  889. }
  890. JET_ERR
  891. GetColumnValue(
  892. IN DWORD Index,
  893. IN LPSTR Buffer,
  894. IN OUT ULONG *BufSize
  895. )
  896. {
  897. JET_ERR Error = NO_ERROR;
  898. DWORD Size;
  899. if( ClientTable[Index].fPresent == FALSE ) {
  900. (*BufSize) = 0;
  901. return NO_ERROR;
  902. }
  903. Error = JetRetrieveColumn(
  904. JetSession, JetTbl, ClientTable[Index].ColHandle, Buffer,
  905. *BufSize, &Size, 0, NULL );
  906. if( JET_errColumnNotFound == Error ) {
  907. Error = NO_ERROR;
  908. Size = 0;
  909. }
  910. Tr("JetRetrieveColumn(%ld): %ld\n", Index, Error );
  911. if( Error < 0 ) return Error;
  912. (*BufSize) = Size;
  913. return NO_ERROR;
  914. }
  915. JET_ERR
  916. SetColumnValue(
  917. IN DWORD Index,
  918. IN LPSTR Buffer,
  919. IN ULONG BufSize
  920. )
  921. {
  922. JET_ERR Error = NO_ERROR;
  923. if( ClientTable[Index].fPresent == FALSE ) {
  924. return ERROR_CAN_NOT_COMPLETE;
  925. }
  926. Error = JetSetColumn(
  927. JetSession, JetTbl, ClientTable[Index].ColHandle, Buffer,
  928. BufSize, 0, NULL );
  929. Tr("JetSetColumn(%ld): %ld\n", Index, Error );
  930. if( Error < 0 ) return Error;
  931. return NO_ERROR;
  932. }
  933. #define CLIENT_TYPE_UNSPECIFIED 0x0 // for backward compatibility
  934. #define CLIENT_TYPE_DHCP 0x1
  935. #define CLIENT_TYPE_BOOTP 0x2
  936. #define CLIENT_TYPE_BOTH ( CLIENT_TYPE_DHCP | CLIENT_TYPE_BOOTP )
  937. #define ADDRESS_STATE_OFFERED 0
  938. #define ADDRESS_STATE_ACTIVE 1
  939. #define ADDRESS_STATE_DECLINED 2
  940. #define ADDRESS_STATE_DOOM 3
  941. #define ADDRESS_BIT_DELETED 0x80
  942. #define ADDRESS_BIT_UNREGISTERED 0x40
  943. #define ADDRESS_BIT_BOTH_REC 0x20
  944. #define ADDRESS_BIT_CLEANUP 0x10
  945. #define ADDRESS_BITS_MASK 0xF0
  946. DWORD
  947. AddRecord(
  948. IN LPSTR Buffer,
  949. IN ULONG BufSize
  950. );
  951. DWORD
  952. AddScannedClient(
  953. IN DWORD IpAddressNetOrder,
  954. IN DWORD SubnetMaskNetOrder,
  955. IN LPBYTE HwAddr,
  956. IN ULONG HwLen,
  957. IN LPWSTR MachineName,
  958. IN LPWSTR MachineInfo,
  959. IN ULONGLONG ExpirationFileTime,
  960. IN BYTE State,
  961. IN BYTE ClientType
  962. )
  963. {
  964. DWORD i;
  965. CHAR Buffer[1024];
  966. ULONG Length, Size;
  967. Length = 0;
  968. Buffer[Length++] = (BYTE)RecordTypeDbEntry;
  969. CopyMemory(
  970. &Buffer[Length], (PVOID)&IpAddressNetOrder, sizeof(DWORD) );
  971. Length += sizeof(DWORD);
  972. CopyMemory(
  973. &Buffer[Length], (PVOID)&SubnetMaskNetOrder, sizeof(DWORD) );
  974. Length += sizeof(DWORD);
  975. Buffer[Length++] = (BYTE)HwLen;
  976. CopyMemory(&Buffer[Length], HwAddr, HwLen );
  977. Length += HwLen;
  978. if( NULL == MachineName || 0 == *MachineName ) Size = 0;
  979. else Size = sizeof(WCHAR)*(1+wcslen(MachineName));
  980. CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
  981. Length += sizeof(DWORD);
  982. if ( NULL != MachineName ) {
  983. CopyMemory(&Buffer[Length], (PVOID)MachineName, Size );
  984. Length += Size;
  985. }
  986. if( NULL == MachineInfo || 0 == *MachineInfo ) Size = 0;
  987. else Size = sizeof(WCHAR)*(1+wcslen(MachineInfo));
  988. CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
  989. Length += sizeof(DWORD);
  990. if ( NULL != MachineInfo ) {
  991. CopyMemory(&Buffer[Length], (PVOID)MachineInfo, Size );
  992. Length += Size;
  993. }
  994. CopyMemory(&Buffer[Length], (PVOID)&ExpirationFileTime, sizeof(ULONGLONG));
  995. Length += sizeof(ULONGLONG);
  996. Buffer[Length++] = State;
  997. Buffer[Length++] = ClientType;
  998. return AddRecord( Buffer, Length );
  999. }
  1000. BOOL
  1001. SubnetNotSelected(
  1002. IN ULONG Subnet,
  1003. IN PULONG Subnets,
  1004. IN ULONG nSubnets
  1005. )
  1006. {
  1007. if( nSubnets == 0 ) return FALSE;
  1008. while( nSubnets -- ) {
  1009. if( Subnet == *Subnets++ ) return FALSE;
  1010. }
  1011. return TRUE;
  1012. }
  1013. DWORD static
  1014. ScanDatabase(
  1015. IN PULONG Subnets,
  1016. IN ULONG nSubnets
  1017. )
  1018. {
  1019. LONG Error;
  1020. DWORD Count;
  1021. Error = JetSetCurrentIndex(
  1022. JetSession, JetTbl, NULL );
  1023. Tr("JetSetCurrentIndex: %ld\n", Error );
  1024. if( Error < 0 ) return Error;
  1025. Error = JetMove( JetSession, JetTbl, JET_MoveFirst, 0 );
  1026. for( Count = 0 ; Error >= 0 ; Count ++,
  1027. Error = JetMove(JetSession, JetTbl, JET_MoveNext, 0) ) {
  1028. DWORD IpAddress, SubnetMask, Size, HwLen;
  1029. FILETIME Expiration;
  1030. CHAR HwAddress[256];
  1031. WCHAR MachineName[300], MachineInfo[300];
  1032. BYTE Type, State;
  1033. //
  1034. // Get current client's info.
  1035. //
  1036. Size = sizeof(IpAddress);
  1037. Error = GetColumnValue(
  1038. IPADDRESS_INDEX, (PVOID)&IpAddress, &Size );
  1039. if( NO_ERROR != Error ) break;
  1040. if( Size != sizeof(IpAddress) ) {
  1041. Tr("Invalid Ip size\n");
  1042. continue;
  1043. }
  1044. Size = sizeof(SubnetMask);
  1045. Error = GetColumnValue(
  1046. SUBNET_MASK_INDEX, (PVOID)&SubnetMask, &Size );
  1047. if( NO_ERROR != Error ) break;
  1048. if( Size != sizeof(SubnetMask) ) {
  1049. Tr("Invalid mask size\n");
  1050. continue;
  1051. }
  1052. //
  1053. // Check if the subnet specified matches the specific
  1054. // subnet
  1055. //
  1056. if( SubnetNotSelected(
  1057. IpAddress&SubnetMask, Subnets, nSubnets ) ) {
  1058. continue;
  1059. }
  1060. HwLen = sizeof(HwAddress);
  1061. Error = GetColumnValue(
  1062. HARDWARE_ADDRESS_INDEX, (PVOID)HwAddress, &HwLen );
  1063. if( NO_ERROR != Error ) break;
  1064. Size = sizeof(MachineName);
  1065. Error = GetColumnValue(
  1066. MACHINE_NAME_INDEX, (PVOID)MachineName, &Size );
  1067. if( NO_ERROR != Error ) break;
  1068. if( (Size % 2) != 0 ) {
  1069. Tr("Invalid name size\n");
  1070. continue;
  1071. }
  1072. MachineName[Size/2] = L'\0';
  1073. Size = sizeof(MachineInfo);
  1074. Error = GetColumnValue(
  1075. MACHINE_INFO_INDEX, (PVOID)MachineInfo, &Size );
  1076. if( NO_ERROR != Error ) break;
  1077. if( (Size % 2) != 0 ) {
  1078. Tr("Invalid Info size\n");
  1079. continue;
  1080. }
  1081. MachineInfo[Size/2] = L'\0';
  1082. Size = sizeof(Expiration);
  1083. Error = GetColumnValue(
  1084. LEASE_TERMINATE_INDEX, (PVOID)&Expiration, &Size );
  1085. if( NO_ERROR != Error ) break;
  1086. if( Size != sizeof(Expiration) ) {
  1087. Tr("Invalid expiration\n");
  1088. Error = ERROR_INVALID_DATA;
  1089. break;
  1090. }
  1091. Size = sizeof(Type);
  1092. Error = GetColumnValue(
  1093. CLIENT_TYPE_INDEX, (PVOID)&Type, &Size );
  1094. if( NO_ERROR != Error || 0 == Size ) {
  1095. Type = CLIENT_TYPE_DHCP;
  1096. }
  1097. Size = sizeof(State);
  1098. Error = GetColumnValue(
  1099. STATE_INDEX, (PVOID)&State, &Size );
  1100. if( NO_ERROR != Error || 0 == Size ) {
  1101. State = ADDRESS_STATE_ACTIVE;
  1102. }
  1103. if( ADDRESS_STATE_OFFERED == State ) {
  1104. continue;
  1105. }
  1106. //
  1107. // Try to add the client
  1108. //
  1109. Error = AddScannedClient(
  1110. ByteSwap(IpAddress), ByteSwap(SubnetMask), HwAddress, HwLen,
  1111. MachineName, MachineInfo, *(PULONGLONG)&Expiration,
  1112. State, Type );
  1113. if( NO_ERROR != Error ) break;
  1114. }
  1115. Tr("Scanned %ld clients\n", Count );
  1116. if( JET_errNoCurrentRecord == Error ) return NO_ERROR;
  1117. if( Error < 0 ) return Error;
  1118. return NO_ERROR;
  1119. }
  1120. DWORD
  1121. DumpData(
  1122. IN LPSTR Buffer,
  1123. IN ULONG BufSize
  1124. )
  1125. {
  1126. return NO_ERROR;
  1127. }
  1128. DWORD
  1129. AddRecord(
  1130. IN LPSTR Buffer,
  1131. IN ULONG BufSize
  1132. )
  1133. {
  1134. DWORD Written, Error = NO_ERROR;
  1135. if( NULL != Buffer ) {
  1136. CopyMemory(&SaveBuf[SaveBufSize], (PVOID)&BufSize, sizeof(DWORD));
  1137. CopyMemory(&SaveBuf[SaveBufSize+sizeof(DWORD)], Buffer, BufSize );
  1138. } else {
  1139. if( 0 == SaveBufSize ) return NO_ERROR;
  1140. if( FALSE == WriteFile(
  1141. hTextFile, SaveBuf, SaveBufSize, &Written, NULL ) ) {
  1142. return GetLastError();
  1143. }
  1144. if( Written != SaveBufSize ) {
  1145. ASSERT(FALSE);
  1146. return ERROR_CAN_NOT_COMPLETE;
  1147. }
  1148. return NO_ERROR;
  1149. }
  1150. if( SaveBufSize <= SAVE_THRESHOLD ) {
  1151. SaveBufSize += BufSize + sizeof(DWORD);
  1152. } else {
  1153. if( FALSE == WriteFile(
  1154. hTextFile, SaveBuf, SaveBufSize + BufSize + sizeof(DWORD),
  1155. &Written, NULL )) {
  1156. return GetLastError();
  1157. }
  1158. if( Written != SaveBufSize + BufSize + sizeof(DWORD) ) {
  1159. ASSERT(FALSE);
  1160. return ERROR_CAN_NOT_COMPLETE;
  1161. }
  1162. SaveBufSize = 0;
  1163. }
  1164. return Error;
  1165. }
  1166. DWORD
  1167. AddRecordNoSize(
  1168. IN LPSTR Buffer,
  1169. IN ULONG BufSize
  1170. )
  1171. {
  1172. DWORD Written, Error = NO_ERROR;
  1173. if( NULL != Buffer ) {
  1174. CopyMemory(&SaveBuf[SaveBufSize], Buffer, BufSize );
  1175. } else {
  1176. if( 0 == SaveBufSize ) return NO_ERROR;
  1177. if( FALSE == WriteFile(
  1178. hTextFile, SaveBuf, SaveBufSize, &Written, NULL ) ) {
  1179. return GetLastError();
  1180. }
  1181. if( Written != SaveBufSize ) {
  1182. ASSERT(FALSE);
  1183. return ERROR_CAN_NOT_COMPLETE;
  1184. }
  1185. return NO_ERROR;
  1186. }
  1187. if( SaveBufSize <= SAVE_THRESHOLD ) {
  1188. SaveBufSize += BufSize;
  1189. } else {
  1190. if( FALSE == WriteFile(
  1191. hTextFile, SaveBuf, SaveBufSize + BufSize,
  1192. &Written, NULL )) {
  1193. return GetLastError();
  1194. }
  1195. if( Written != SaveBufSize + BufSize ) {
  1196. ASSERT(FALSE);
  1197. return ERROR_CAN_NOT_COMPLETE;
  1198. }
  1199. SaveBufSize = 0;
  1200. }
  1201. return Error;
  1202. }
  1203. DWORD
  1204. StopDhcpService(
  1205. VOID
  1206. )
  1207. {
  1208. SC_HANDLE hSc, hSvc;
  1209. DWORD Error;
  1210. Error = NO_ERROR;
  1211. hSc = NULL;
  1212. hSvc = NULL;
  1213. do {
  1214. hSc = OpenSCManager(
  1215. NULL, NULL, SC_MANAGER_CONNECT | GENERIC_READ | GENERIC_WRITE );
  1216. if( NULL == hSc ) {
  1217. Error = GetLastError();
  1218. Tr("OpenSCManager: %ld\n", Error );
  1219. break;
  1220. }
  1221. hSvc = OpenService(
  1222. hSc, TEXT("DHCPServer"), SERVICE_STOP| SERVICE_QUERY_STATUS );
  1223. if( NULL == hSvc ) {
  1224. Error = GetLastError();
  1225. Tr("OpenService: %ld\n", Error );
  1226. break;
  1227. }
  1228. while( NO_ERROR == Error ) {
  1229. SERVICE_STATUS Status;
  1230. if( FALSE == QueryServiceStatus( hSvc, &Status ) ) {
  1231. Error = GetLastError();
  1232. Tr( "QueryServiceStatus: %ld\n", Error );
  1233. break;
  1234. }
  1235. if( Status.dwCurrentState == SERVICE_STOPPED ) break;
  1236. if( Status.dwCurrentState != SERVICE_RUNNING &&
  1237. Status.dwCurrentState != SERVICE_PAUSED ) {
  1238. Tr( "Waiting, state = %ld\n", Status.dwCurrentState );
  1239. if( Status.dwWaitHint < 1000 ) {
  1240. Status.dwWaitHint = 1000;
  1241. }
  1242. if( Status.dwWaitHint > 5000 ) {
  1243. Status.dwWaitHint = 1000;
  1244. }
  1245. Sleep(Status.dwWaitHint);
  1246. } else {
  1247. Error = ControlService(
  1248. hSvc, SERVICE_CONTROL_STOP, &Status );
  1249. if( FALSE != Error ) Error = NO_ERROR;
  1250. else {
  1251. Error = GetLastError();
  1252. Tr("ControlService: %ld\n", Error );
  1253. break;
  1254. }
  1255. }
  1256. }
  1257. } while( 0 );
  1258. if( NULL != hSvc ) CloseServiceHandle( hSvc );
  1259. if( NULL != hSc ) CloseServiceHandle( hSc );
  1260. return Error;
  1261. }
  1262. DWORD
  1263. StartDhcpService(
  1264. VOID
  1265. )
  1266. {
  1267. SC_HANDLE hSc, hSvc;
  1268. DWORD Error;
  1269. Error = NO_ERROR;
  1270. hSc = NULL;
  1271. hSvc = NULL;
  1272. do {
  1273. hSc = OpenSCManager(
  1274. NULL, NULL, SC_MANAGER_CONNECT | GENERIC_READ | GENERIC_WRITE );
  1275. if( NULL == hSc ) {
  1276. Error = GetLastError();
  1277. Tr("OpenSCManager: %ld\n", Error );
  1278. break;
  1279. }
  1280. hSvc = OpenService(
  1281. hSc, TEXT("DHCPServer"), SERVICE_START| SERVICE_QUERY_STATUS );
  1282. if( NULL == hSvc ) {
  1283. Error = GetLastError();
  1284. Tr("OpenService: %ld\n", Error );
  1285. break;
  1286. }
  1287. Error = StartService( hSvc, 0, NULL );
  1288. if( FALSE == Error ) Error = GetLastError(); else Error = NO_ERROR;
  1289. if( NO_ERROR != Error ) break;
  1290. while( NO_ERROR == Error ) {
  1291. SERVICE_STATUS Status;
  1292. if( FALSE == QueryServiceStatus( hSvc, &Status ) ) {
  1293. Error = GetLastError();
  1294. Tr("QueryServiceStatus: %ld\n", Error );
  1295. break;
  1296. }
  1297. if( Status.dwCurrentState == SERVICE_RUNNING ) break;
  1298. if( Status.dwCurrentState == SERVICE_START_PENDING ) {
  1299. Tr("Sleeping %ld\n", Status.dwWaitHint );
  1300. if( Status.dwWaitHint < 1000 ) {
  1301. Status.dwWaitHint = 1000;
  1302. }
  1303. if( Status.dwWaitHint > 5000 ) {
  1304. Status.dwWaitHint = 5000;
  1305. }
  1306. Sleep(Status.dwWaitHint);
  1307. } else {
  1308. Error = ERROR_CAN_NOT_COMPLETE;
  1309. break;
  1310. }
  1311. }
  1312. } while( 0 );
  1313. if( NULL != hSvc ) CloseServiceHandle( hSvc );
  1314. if( NULL != hSc ) CloseServiceHandle( hSc );
  1315. return Error;
  1316. }
  1317. DWORD __stdcall PrintRecord(
  1318. IN PDHCP_RECORD Recx
  1319. )
  1320. {
  1321. DWORD i;
  1322. DHCP_RECORD Rec = *Recx;
  1323. if( Rec.fMcast ) {
  1324. printf("Mcast Record\n" );
  1325. printf("Address: %s\n", IpAddressToString(
  1326. Rec.Info.Mcast.Address ));
  1327. printf("ScopeId: %s\n", IpAddressToString(
  1328. Rec.Info.Mcast.ScopeId ));
  1329. printf("ClientId:");
  1330. for( i = 0 ; i < (DWORD)Rec.Info.Mcast.HwLen; i ++ ) {
  1331. printf(" %02X", Rec.Info.Mcast.ClientId[i]);
  1332. }
  1333. printf("\nState = %02X\n", Rec.Info.Mcast.State);
  1334. } else {
  1335. printf("DHCP Record\n" );
  1336. printf("Address: %s\n", IpAddressToString(
  1337. Rec.Info.Dhcp.Address ));
  1338. printf("Mask: %s\n", IpAddressToString(
  1339. Rec.Info.Dhcp.Mask ));
  1340. printf("ClientId:");
  1341. for( i = 0 ; i < (DWORD)Rec.Info.Dhcp.HwLen; i ++ ) {
  1342. printf(" %02X", Rec.Info.Dhcp.HwAddr[i]);
  1343. }
  1344. printf("\nState = %02X\n", Rec.Info.Dhcp.State);
  1345. printf("\nType = %02X\n", Rec.Info.Dhcp.Type);
  1346. if( Rec.Info.Dhcp.Name ) {
  1347. printf("Name = %ws\n", Rec.Info.Dhcp.Name );
  1348. }
  1349. if( Rec.Info.Dhcp.Info ) {
  1350. printf("Comment = %ws\n", Rec.Info.Dhcp.Info );
  1351. }
  1352. }
  1353. return NO_ERROR;
  1354. }
  1355. DWORD
  1356. StringLen(
  1357. IN WCHAR UNALIGNED *Str
  1358. )
  1359. {
  1360. DWORD Size = sizeof(WCHAR);
  1361. if( NULL == Str ) return 0;
  1362. while( *Str ++ != L'\0' ) Size += sizeof(WCHAR);
  1363. return Size;
  1364. }
  1365. DWORD __stdcall
  1366. AddRecordToDatabase(
  1367. IN PDHCP_RECORD Recx
  1368. )
  1369. {
  1370. DWORD Index;
  1371. JET_ERR Error;
  1372. DHCP_RECORD Rec = *Recx;
  1373. WCHAR Address[30], HwAddress[300];
  1374. IpAddressToStringW(Rec.Info.Dhcp.Address, Address);
  1375. DhcpHexToString(
  1376. HwAddress, Rec.Info.Dhcp.HwAddr,
  1377. Rec.Info.Dhcp.HwLen );
  1378. Error = JetBeginTransaction( JetSession );
  1379. Tr( "JetBeginTransaction: %ld\n", Error );
  1380. if( Error < 0 ) return Error;
  1381. do {
  1382. Error = JetPrepareUpdate( JetSession, JetTbl, JET_prepInsert );
  1383. if( Error ) Tr( "JetPrepareUpdate: %ld\n", Error );
  1384. if( Error < 0 ) break;
  1385. Index = IPADDRESS_INDEX;
  1386. Error = SetColumnValue(
  1387. Index, (LPBYTE)&Rec.Info.Dhcp.Address, sizeof(DWORD) );
  1388. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1389. if( Error < 0 ) break;
  1390. Index = SUBNET_MASK_INDEX;
  1391. Error = SetColumnValue(
  1392. Index, (LPBYTE)&Rec.Info.Dhcp.Mask, sizeof(DWORD) );
  1393. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1394. if( Error < 0 ) break;
  1395. Index = HARDWARE_ADDRESS_INDEX;
  1396. Error = SetColumnValue(
  1397. Index, Rec.Info.Dhcp.HwAddr, Rec.Info.Dhcp.HwLen );
  1398. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1399. if( Error < 0 ) break;
  1400. Index = STATE_INDEX;
  1401. Error = SetColumnValue(
  1402. Index, &Rec.Info.Dhcp.State, sizeof(BYTE) );
  1403. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1404. if( Error < 0 ) break;
  1405. Index = CLIENT_TYPE_INDEX;
  1406. Error = SetColumnValue(
  1407. Index, &Rec.Info.Dhcp.Type, sizeof(BYTE) );
  1408. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1409. if( Error < 0 ) break;
  1410. Index = MACHINE_INFO_INDEX;
  1411. Error = SetColumnValue(
  1412. Index, (LPBYTE)Rec.Info.Dhcp.Info, StringLen(Rec.Info.Dhcp.Info) );
  1413. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1414. if( Error < 0 ) break;
  1415. Index = MACHINE_NAME_INDEX;
  1416. Error = SetColumnValue(
  1417. Index, (LPBYTE)Rec.Info.Dhcp.Name, StringLen(Rec.Info.Dhcp.Name) );
  1418. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1419. if( Error < 0 ) break;
  1420. Index = LEASE_TERMINATE_INDEX;
  1421. Error = SetColumnValue(
  1422. Index, (LPBYTE)&Rec.Info.Dhcp.ExpTime, sizeof(FILETIME) );
  1423. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1424. if( Error < 0 ) break;
  1425. Index = SERVER_IP_ADDRESS_INDEX;
  1426. Rec.Info.Dhcp.Address = INADDR_LOOPBACK;
  1427. Error = SetColumnValue(
  1428. Index, (LPBYTE)&Rec.Info.Dhcp.Address, sizeof(DWORD));
  1429. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1430. if( Error < 0 ) break;
  1431. Index = SERVER_NAME_INDEX;
  1432. Rec.Info.Dhcp.Name = L"";
  1433. Error = SetColumnValue(
  1434. Index, (LPBYTE)Rec.Info.Dhcp.Name, StringLen(Rec.Info.Dhcp.Name));
  1435. if( Error ) Tr( "SetColumnValue(%ld): %ld\n", Index, Error );
  1436. if( Error < 0 ) break;
  1437. Error = JetUpdate( JetSession, JetTbl, NULL, 0, NULL );
  1438. if( Error ) Tr( "JetUpdate: %ld\n", Error );
  1439. if( Error < 0 ) break;
  1440. } while ( 0 );
  1441. if( Error < 0 ) {
  1442. BOOL fAbort;
  1443. JetRollback( JetSession, 0 );
  1444. fAbort = TRUE;
  1445. DhcpEximErrorDatabaseEntryFailed(
  1446. Address, HwAddress, Error, &fAbort );
  1447. if( fAbort ) return ERROR_CAN_NOT_COMPLETE;
  1448. } else {
  1449. JetCommitTransaction( JetSession, 0 );
  1450. }
  1451. return NO_ERROR;
  1452. }
  1453. DWORD
  1454. ProcessDbEntries(
  1455. IN LPSTR Buffer,
  1456. IN ULONG BufSize,
  1457. IN PULONG Subnets,
  1458. IN ULONG nSubnets,
  1459. IN DHCP_ADD_RECORD_ROUTINE AddRec
  1460. )
  1461. {
  1462. DWORD Size, ThisSize, DbEntry;
  1463. LPSTR Buf;
  1464. DWORD Address, i, Error;
  1465. FILETIME Time;
  1466. DHCP_RECORD Rec;
  1467. Error = NO_ERROR;
  1468. while( BufSize > sizeof(DWORD) ) {
  1469. CopyMemory(&ThisSize, Buffer, sizeof(DWORD));
  1470. Buffer += sizeof(DWORD);
  1471. BufSize -= sizeof(DWORD);
  1472. if( ThisSize > BufSize ) return ERROR_INVALID_DATA;
  1473. if( ThisSize == 0 ) continue;
  1474. DbEntry = *Buffer;
  1475. Buf = Buffer+1;
  1476. Buffer += ThisSize;
  1477. BufSize -= ThisSize;
  1478. ZeroMemory( &Rec, sizeof(Rec));
  1479. switch(DbEntry) {
  1480. default :
  1481. return ERROR_INVALID_DATA;
  1482. case RecordTypeDbEntry :
  1483. Rec.fMcast = FALSE;
  1484. CopyMemory( &Rec.Info.Dhcp.Address, Buf, sizeof(DWORD));
  1485. Rec.Info.Dhcp.Address = ByteSwap(Rec.Info.Dhcp.Address);
  1486. Buf += sizeof(DWORD);
  1487. CopyMemory( &Rec.Info.Dhcp.Mask, Buf, sizeof(DWORD));
  1488. Rec.Info.Dhcp.Mask = ByteSwap(Rec.Info.Dhcp.Mask);
  1489. Buf += sizeof(DWORD);
  1490. Size = Rec.Info.Dhcp.HwLen = *Buf++;
  1491. Rec.Info.Dhcp.HwAddr = Buf;
  1492. Buf += Size;
  1493. CopyMemory(&Size, Buf, sizeof(DWORD));
  1494. Buf += sizeof(DWORD);
  1495. if( Size ) {
  1496. Rec.Info.Dhcp.Name = (PVOID)Buf;
  1497. Buf += Size;
  1498. }
  1499. CopyMemory(&Size, Buf, sizeof(DWORD));
  1500. Buf += sizeof(DWORD);
  1501. if( Size ) {
  1502. Rec.Info.Dhcp.Info = (PVOID)Buf;
  1503. Buf += Size;
  1504. }
  1505. CopyMemory(&Rec.Info.Dhcp.ExpTime, Buf, sizeof(FILETIME));
  1506. Buf += sizeof(FILETIME);
  1507. Rec.Info.Dhcp.State = Buf[0];
  1508. Rec.Info.Dhcp.Type = Buf[1];
  1509. //
  1510. // Add the subnet only if it is selected
  1511. //
  1512. if( !SubnetNotSelected(
  1513. Rec.Info.Dhcp.Address & Rec.Info.Dhcp.Mask,
  1514. Subnets, nSubnets ) ) {
  1515. Error = AddRec( &Rec );
  1516. }
  1517. break;
  1518. case RecordTypeMcastDbEntry :
  1519. Rec.fMcast = TRUE;
  1520. CopyMemory( &Rec.Info.Mcast.Address, Buf, sizeof(DWORD));
  1521. Buf += sizeof(DWORD);
  1522. CopyMemory( &Rec.Info.Mcast.ScopeId, Buf, sizeof(DWORD));
  1523. Buf += sizeof(DWORD);
  1524. Size = Rec.Info.Mcast.HwLen = *Buf++;
  1525. Rec.Info.Mcast.ClientId = Buf;
  1526. Buf += Size;
  1527. CopyMemory(&Size, Buf, sizeof(DWORD));
  1528. Buf += sizeof(DWORD);
  1529. if( Size ) {
  1530. Rec.Info.Mcast.Info = (PVOID)Buf;
  1531. Buf += Size;
  1532. }
  1533. CopyMemory(&Rec.Info.Mcast.End, Buf, sizeof(FILETIME));
  1534. Buf += sizeof(FILETIME);
  1535. CopyMemory(&Rec.Info.Mcast.Start, Buf, sizeof(FILETIME));
  1536. Buf += sizeof(FILETIME);
  1537. Rec.Info.Mcast.State = Buf[0];
  1538. Error = AddRec( &Rec );
  1539. break;
  1540. }
  1541. if( NO_ERROR != Error ) return Error;
  1542. }
  1543. return NO_ERROR;
  1544. }
  1545. DWORD
  1546. SaveDatabaseEntriesToFile(
  1547. IN PULONG Subnets,
  1548. IN ULONG nSubnets
  1549. )
  1550. {
  1551. DWORD Error;
  1552. Error = InitializeDatabase();
  1553. if( NO_ERROR != Error ) {
  1554. Tr("InitializeDatabase: %ld\n", Error );
  1555. return Error;
  1556. }
  1557. Error = ScanDatabase(Subnets, nSubnets);
  1558. if( NO_ERROR != Error ) {
  1559. Tr("ScanDatabase: %ld\n", Error);
  1560. } else {
  1561. AddRecord( NULL, 0 );
  1562. }
  1563. CleanupDatabase();
  1564. return Error;
  1565. }
  1566. DWORD
  1567. SaveFileEntriesToDatabase(
  1568. IN LPBYTE Mem,
  1569. IN ULONG MemSize,
  1570. IN PULONG Subnets,
  1571. IN ULONG nSubnets
  1572. )
  1573. {
  1574. DWORD Error;
  1575. Error = InitializeDatabase();
  1576. if( NO_ERROR != Error ) {
  1577. Tr("InitializeDatabase: %ld\n", Error );
  1578. return Error;
  1579. }
  1580. Error = ProcessDbEntries(
  1581. Mem, MemSize, Subnets, nSubnets, AddRecordToDatabase );
  1582. if( NO_ERROR != Error ) {
  1583. Tr("ProcessDbEntries: %ld\n", Error );
  1584. }
  1585. CleanupDatabase();
  1586. return Error;
  1587. }
  1588. DWORD
  1589. InitializeDatabaseParameters(
  1590. VOID
  1591. )
  1592. {
  1593. DWORD Error;
  1594. //
  1595. // Stop the service
  1596. //
  1597. Error = StopDhcpService();
  1598. if( NO_ERROR != Error ) {
  1599. Tr("StopDhcpService: %ld\n", Error );
  1600. return Error;
  1601. }
  1602. //
  1603. // Read the registry and otherwise initialize the database
  1604. // parameters, without actually opening the database.
  1605. //
  1606. Error = ReadRegistry();
  1607. Tr("ReadRegistry: %ld\n", Error );
  1608. if( NO_ERROR != Error ) return Error;
  1609. Error = ConvertPermissionsOnDbFiles();
  1610. Tr("ConvertPermissionsOnDbFiles: %ld\n", Error );
  1611. // ignore error and try best effort
  1612. if( FALSE == SetCurrentDirectoryA(DatabasePath) ) {
  1613. Error = GetLastError();
  1614. if( ERROR_FILE_NOT_FOUND == Error ||
  1615. ERROR_PATH_NOT_FOUND == Error ) {
  1616. return ERROR_SERVICE_DOES_NOT_EXIST;
  1617. }
  1618. return Error;
  1619. }
  1620. return NO_ERROR;
  1621. }
  1622. DWORD
  1623. CleanupDatabaseParameters(
  1624. VOID
  1625. )
  1626. {
  1627. DWORD Error;
  1628. Error = StartDhcpService();
  1629. if( NO_ERROR != Error ) {
  1630. Tr("StartDhcpService: %ld\n", Error );
  1631. }
  1632. return Error;
  1633. }