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.

2709 lines
70 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. db.c
  5. Abstract:
  6. Upgrade databases from NT3.51, NT4.0 and NT5.0 to Whistler.
  7. N.B: Most of this is taken from dhcp\server\server\database.c
  8. --*/
  9. #include <upgrade.h>
  10. //
  11. // Debugging and logging
  12. //
  13. typedef enum {
  14. Winnt32LogSevereError,
  15. Winnt32LogError,
  16. Winnt32LogWarning,
  17. Winnt32LogInformation,
  18. Winnt32LogDetailedInformation,
  19. Winnt32LogMax
  20. } Winnt32DebugLevel;
  21. HANDLE hInst;
  22. HANDLE hDebugLog;
  23. Winnt32DebugLevel DebugLevel;
  24. typedef DWORD (WINAPI *GetClusterStateFn)( LPCWSTR, DWORD*);
  25. ULONG
  26. ByteSwap(
  27. IN ULONG Source
  28. )
  29. {
  30. ULONG swapped;
  31. swapped = ((Source) << (8 * 3)) |
  32. ((Source & 0x0000FF00) << (8 * 1)) |
  33. ((Source & 0x00FF0000) >> (8 * 1)) |
  34. ((Source) >> (8 * 3));
  35. return swapped;
  36. }
  37. LPSTR
  38. IpAddressToString(
  39. IN ULONG Address
  40. )
  41. {
  42. static CHAR Buffer[30];
  43. PUCHAR pAddress;
  44. pAddress = (PUCHAR)&Address;
  45. sprintf(Buffer, "%d.%d.%d.%d", pAddress[0], pAddress[1],
  46. pAddress[2], pAddress[3] );
  47. return Buffer;
  48. }
  49. VOID
  50. ConcatenatePaths(
  51. IN OUT PTSTR Path1,
  52. IN LPCTSTR Path2,
  53. IN DWORD BufferSizeChars
  54. )
  55. /*++
  56. Routine Description:
  57. Concatenate two path strings together, supplying a path separator
  58. character (\) if necessary between the 2 parts.
  59. Arguments:
  60. Path1 - supplies prefix part of path. Path2 is concatenated to Path1.
  61. Path2 - supplies the suffix part of path. If Path1 does not end with a
  62. path separator and Path2 does not start with one, then a path sep
  63. is appended to Path1 before appending Path2.
  64. BufferSizeChars - supplies the size in chars (Unicode version) or
  65. bytes (Ansi version) of the buffer pointed to by Path1. The string
  66. will be truncated as necessary to not overflow that size.
  67. Return Value:
  68. None.
  69. --*/
  70. {
  71. BOOL NeedBackslash = TRUE;
  72. DWORD l;
  73. if(!Path1)
  74. return;
  75. l = lstrlen(Path1);
  76. if(BufferSizeChars >= sizeof(TCHAR)) {
  77. //
  78. // Leave room for terminating nul.
  79. //
  80. BufferSizeChars -= sizeof(TCHAR);
  81. }
  82. //
  83. // Determine whether we need to stick a backslash
  84. // between the components.
  85. //
  86. if(l && (Path1[l-1] == TEXT('\\'))) {
  87. NeedBackslash = FALSE;
  88. }
  89. if(Path2 && *Path2 == TEXT('\\')) {
  90. if(NeedBackslash) {
  91. NeedBackslash = FALSE;
  92. } else {
  93. //
  94. // Not only do we not need a backslash, but we
  95. // need to eliminate one before concatenating.
  96. //
  97. Path2++;
  98. }
  99. }
  100. //
  101. // Append backslash if necessary and if it fits.
  102. //
  103. if(NeedBackslash && (l < BufferSizeChars)) {
  104. lstrcat(Path1,TEXT("\\"));
  105. }
  106. //
  107. // Append second part of string to first part if it fits.
  108. //
  109. if(Path2 && ((l+lstrlen(Path2)) < BufferSizeChars)) {
  110. lstrcat(Path1,Path2);
  111. }
  112. }
  113. LPTSTR
  114. DupString(
  115. IN LPCTSTR String
  116. )
  117. /*++
  118. Routine Description:
  119. Make a duplicate of a nul-terminated string.
  120. Arguments:
  121. String - supplies pointer to nul-terminated string to copy.
  122. Return Value:
  123. Copy of string or NULL if OOM. Caller can free with FREE().
  124. --*/
  125. {
  126. LPTSTR p;
  127. if(p = LocalAlloc(LPTR, (lstrlen(String)+1)*sizeof(TCHAR))) {
  128. lstrcpy(p,String);
  129. }
  130. return(p);
  131. }
  132. /***
  133. *void Parse_Cmdline(cmdstart, argv, lpstr, numargs, numbytes)
  134. *
  135. *Purpose:
  136. * Parses the command line and sets up the Unicode argv[] array.
  137. * On entry, cmdstart should point to the command line,
  138. * argv should point to memory for the argv array, lpstr
  139. * points to memory to place the text of the arguments.
  140. * If these are NULL, then no storing (only counting)
  141. * is done. On exit, *numargs has the number of
  142. * arguments (plus one for a final NULL argument),
  143. * and *numbytes has the number of bytes used in the buffer
  144. * pointed to by args.
  145. *
  146. *Entry:
  147. * LPWSTR cmdstart - pointer to command line of the form
  148. * <progname><nul><args><nul>
  149. * TCHAR **argv - where to build argv array; NULL means don't
  150. * build array
  151. * LPWSTR lpstr - where to place argument text; NULL means don't
  152. * store text
  153. *
  154. *Exit:
  155. * no return value
  156. * INT *numargs - returns number of argv entries created
  157. * INT *numbytes - number of bytes used in args buffer
  158. *
  159. *Exceptions:
  160. *
  161. *******************************************************************************/
  162. void Parse_Cmdline (
  163. LPTSTR cmdstart,
  164. LPTSTR*argv,
  165. LPTSTR lpstr,
  166. INT *numargs,
  167. INT *numbytes
  168. )
  169. {
  170. LPTSTR p;
  171. TCHAR c;
  172. INT inquote; /* 1 = inside quotes */
  173. INT copychar; /* 1 = copy char to *args */
  174. WORD numslash; /* num of backslashes seen */
  175. *numbytes = 0;
  176. *numargs = 1; /* the program name at least */
  177. /* first scan the program name, copy it, and count the bytes */
  178. p = cmdstart;
  179. if (argv)
  180. *argv++ = lpstr;
  181. /* A quoted program name is handled here. The handling is much
  182. simpler than for other arguments. Basically, whatever lies
  183. between the leading double-quote and next one, or a terminal null
  184. character is simply accepted. Fancier handling is not required
  185. because the program name must be a legal NTFS/HPFS file name.
  186. Note that the double-quote characters are not copied, nor do they
  187. contribute to numbytes. */
  188. if (*p == TEXT('\"'))
  189. {
  190. /* scan from just past the first double-quote through the next
  191. double-quote, or up to a null, whichever comes first */
  192. while ((*(++p) != TEXT('\"')) && (*p != TEXT('\0')))
  193. {
  194. *numbytes += sizeof(WCHAR);
  195. if (lpstr)
  196. *lpstr++ = *p;
  197. }
  198. /* append the terminating null */
  199. *numbytes += sizeof(WCHAR);
  200. if (lpstr)
  201. *lpstr++ = TEXT('\0');
  202. /* if we stopped on a double-quote (usual case), skip over it */
  203. if (*p == TEXT('\"'))
  204. p++;
  205. }
  206. else
  207. {
  208. /* Not a quoted program name */
  209. do {
  210. *numbytes += sizeof(WCHAR);
  211. if (lpstr)
  212. *lpstr++ = *p;
  213. c = *p++;
  214. } while (c > TEXT(' '));
  215. if (c == TEXT('\0'))
  216. {
  217. p--;
  218. }
  219. else
  220. {
  221. if (lpstr)
  222. *(lpstr - 1) = TEXT('\0');
  223. }
  224. }
  225. inquote = 0;
  226. /* loop on each argument */
  227. for ( ; ; )
  228. {
  229. if (*p)
  230. {
  231. while (*p == TEXT(' ') || *p == TEXT('\t'))
  232. ++p;
  233. }
  234. if (*p == TEXT('\0'))
  235. break; /* end of args */
  236. /* scan an argument */
  237. if (argv)
  238. *argv++ = lpstr; /* store ptr to arg */
  239. ++*numargs;
  240. /* loop through scanning one argument */
  241. for ( ; ; )
  242. {
  243. copychar = 1;
  244. /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
  245. 2N+1 backslashes + " ==> N backslashes + literal "
  246. N backslashes ==> N backslashes */
  247. numslash = 0;
  248. while (*p == TEXT('\\'))
  249. {
  250. /* count number of backslashes for use below */
  251. ++p;
  252. ++numslash;
  253. }
  254. if (*p == TEXT('\"'))
  255. {
  256. /* if 2N backslashes before, start/end quote, otherwise
  257. copy literally */
  258. if (numslash % 2 == 0)
  259. {
  260. if (inquote)
  261. if (p[1] == TEXT('\"'))
  262. p++; /* Double quote inside quoted string */
  263. else /* skip first quote char and copy second */
  264. copychar = 0;
  265. else
  266. copychar = 0; /* don't copy quote */
  267. inquote = !inquote;
  268. }
  269. numslash /= 2; /* divide numslash by two */
  270. }
  271. /* copy slashes */
  272. while (numslash--)
  273. {
  274. if (lpstr)
  275. *lpstr++ = TEXT('\\');
  276. *numbytes += sizeof(WCHAR);
  277. }
  278. /* if at end of arg, break loop */
  279. if (*p == TEXT('\0') || (!inquote && (*p == TEXT(' ') || *p == TEXT('\t'))))
  280. break;
  281. /* copy character into argument */
  282. if (copychar)
  283. {
  284. if (lpstr)
  285. *lpstr++ = *p;
  286. *numbytes += sizeof(WCHAR);
  287. }
  288. ++p;
  289. }
  290. /* null-terminate the argument */
  291. if (lpstr)
  292. *lpstr++ = TEXT('\0'); /* terminate string */
  293. *numbytes += sizeof(WCHAR);
  294. }
  295. }
  296. LPTSTR *
  297. CommandLineToArgv(
  298. OUT int *NumArgs
  299. )
  300. {
  301. LPTSTR CommandLine;
  302. TCHAR ModuleName[MAX_PATH];
  303. LPTSTR Start;
  304. INT Size;
  305. LPTSTR *Args;
  306. CommandLine = GetCommandLine();
  307. GetModuleFileName(NULL,ModuleName,MAX_PATH);
  308. //
  309. // If there's no command line at all (won't happen from cmd.exe, but
  310. // possibly another program), then we use pgmname as the command line
  311. // to parse, so that argv[0] is initialized to the program name
  312. //
  313. Start = *CommandLine ? CommandLine : ModuleName;
  314. //
  315. // Find out how much space is needed to store args,
  316. // allocate space for argv[] vector and strings,
  317. // and store args and argv ptrs in block we allocate
  318. //
  319. Parse_Cmdline(Start,NULL,NULL,NumArgs,&Size);
  320. Args = (LPTSTR *)LocalAlloc(LMEM_ZEROINIT,((*NumArgs+1) * sizeof(LPTSTR)) + Size);
  321. if(!Args) {
  322. return(NULL);
  323. }
  324. Parse_Cmdline(Start,Args,(LPTSTR)(Args + *NumArgs),NumArgs,&Size);
  325. return(Args);
  326. }
  327. BOOL
  328. StartDebugLog(
  329. IN LPCTSTR DebugFileLog,
  330. IN Winnt32DebugLevel Level
  331. )
  332. {
  333. if( hDebugLog ) return TRUE;
  334. hInst = LoadLibrary(TEXT("DHCPUPG.DLL"));
  335. if(Level >= Winnt32LogMax) Level = Winnt32LogMax-1;
  336. DebugLevel = Level;
  337. hDebugLog = CreateFile(
  338. DebugFileLog, GENERIC_WRITE,
  339. FILE_SHARE_READ, NULL, OPEN_ALWAYS,
  340. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  341. NULL );
  342. if( hDebugLog == INVALID_HANDLE_VALUE) {
  343. hDebugLog = NULL;
  344. return FALSE;
  345. }
  346. if(GetLastError() == ERROR_ALREADY_EXISTS) {
  347. //
  348. // Appending to existing file
  349. //
  350. SetFilePointer(hDebugLog,0,NULL,FILE_END);
  351. }
  352. return(TRUE);
  353. }
  354. VOID
  355. CloseDebugLog(
  356. VOID
  357. )
  358. {
  359. if( hDebugLog ) {
  360. CloseHandle( hDebugLog );
  361. hDebugLog = NULL;
  362. }
  363. }
  364. VOID
  365. StartDebug(
  366. VOID
  367. )
  368. /*++
  369. Routine Description:
  370. Parse arguments passed to the program. Perform syntactic validation
  371. and fill in defaults where necessary.
  372. Valid arguments:
  373. /debug[level][:filename] maintain debug log at level, defaults to warning level 2
  374. and file c:\winnt32.log
  375. /tempdrive:letter manually specify drive for local source
  376. Arguments:
  377. None. Arguments are retreived via GetCommandLine().
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. LPTSTR Arg;
  383. LPTSTR BadParam = NULL;
  384. LPTSTR Colon;
  385. LPTSTR p;
  386. BOOL Valid;
  387. LPCTSTR DebugFileLog;
  388. LONG DebugLevel;
  389. BOOL b;
  390. unsigned u;
  391. int argc;
  392. LPTSTR *argv;
  393. BOOL Downloaded = FALSE;
  394. argv = CommandLineToArgv(&argc);
  395. //
  396. // Skip program name. We should always get back argc as at least 1,
  397. // but be robust anyway.
  398. //
  399. if(argc) {
  400. argc--;
  401. argv++;
  402. }
  403. DebugFileLog = NULL;
  404. DebugLevel = 0;
  405. Valid = FALSE;
  406. while(argc--) {
  407. Arg = *argv++;
  408. if((*Arg == TEXT('/')) || (*Arg == TEXT('-'))) {
  409. switch(_totupper(Arg[1])) {
  410. case TEXT('D'):
  411. if(DebugFileLog || _tcsnicmp(Arg+1,TEXT("debug"),5)) {
  412. break;
  413. }
  414. DebugLevel = _tcstol(Arg+6,&Colon,10);
  415. if((DebugLevel == -1) || (*Colon && (*Colon != TEXT(':')))) {
  416. break;
  417. }
  418. if(Colon == Arg+6) {
  419. //
  420. // No debug level specified, use default
  421. //
  422. DebugLevel = Winnt32LogWarning;
  423. }
  424. if(*Colon) {
  425. //
  426. // Log file name was specified.
  427. //
  428. Colon++;
  429. if(*Colon) {
  430. // Hardcode debug file to
  431. // %windir%\dhcpupg.log for now
  432. // DebugFileLog = Colon;
  433. }
  434. }
  435. break;
  436. }
  437. }
  438. }
  439. if( DebugLevel == 0 || DebugLevel == -1 ) {
  440. DebugLevel = Winnt32LogInformation;
  441. }
  442. if( DebugFileLog == NULL ) {
  443. TCHAR Buffer[MAX_PATH];
  444. if( 0 == GetWindowsDirectory( Buffer, MAX_PATH )) {
  445. ZeroMemory(Buffer, sizeof(Buffer));
  446. }
  447. ConcatenatePaths( Buffer, TEXT("DHCPUPG.LOG"), MAX_PATH );
  448. DebugFileLog = DupString( Buffer );
  449. }
  450. if( DebugFileLog ) Valid = StartDebugLog(DebugFileLog,DebugLevel);
  451. if( !Valid ) {
  452. DbgPrint( "DHCPUPG: Logging not done.\n" );
  453. }
  454. }
  455. struct _MSG_MAP {
  456. DWORD MessageId;
  457. LPWSTR MessageStr;
  458. } MessageMap[] = {
  459. MSGERR_STARTLOG,L"DHCPUPG: ************** Starting conversion to text.\n",
  460. MSGERR_STARTLOG2,L"DHCPUPG: ************** Starting conversion from text.\n",
  461. MSGERR_VALUE,L"DHCPUPG: Error reading registry value %1!s! : %2!d!.\n",
  462. MSGERR_EXPAND,L"DHCPUPG: Error expanding environment variables in string %1!s!.\n",
  463. MSGERR_OPENPARAMSKEY,L"DHCPUPG: Error opening the Parameters key: %1!d!.\n",
  464. MSGERR_GETDBPARAMS,L"DHCPUPG: Successfully read DHCP registry parameters.\n",
  465. MSGERR_LOAD,L"DHCPUPG: %2!s! failed to load: %1!d!.\n",
  466. MSGERR_GETPROCADDR,L"DHCPUPG: Error linking to routine %2!s!: %1!d!.\n",
  467. MSGERR_SETDBPARAM,L"DHCPUPG: Error attempting to set database param %2!d!: %1!d!.\n",
  468. MSGERR_JETINIT,L"DHCPUPG: Error initializing Jet database: %1!d!.\n",
  469. MSGERR_JETBEGINSESSION,L"DHCPUPG: Error initializing Jet session: %1!d!.\n",
  470. MSGERR_JETDETACHDB,L"DHCPUPG: Error detaching Jet database: %1!d!.\n",
  471. MSGERR_JETATTACHDB,L"DHCPUPG: Error attaching Jet database: %1!d!.\n",
  472. MSGERR_JETOPENDB,L"DHCPUPG: Error opening Jet database: %1!d!.\n",
  473. MSGERR_JETOPENTABLE,L"DHCPUPG: Error opening Jet database table: %1!d!.\n",
  474. MSGERR_JETGETCOL,L"DHCPUPG: Error opening Jet table column: %1!d!.\n",
  475. MSGERR_JETOPENMTABLE,L"DHCPUPG: Error opening Jet database mcast table: %1!d!.\n",
  476. MSGERR_JETGETMCOL,L"DHCPUPG: Error opening Jet mcast table column: %1!d!.\n",
  477. MSGERR_INITDB,L"DHCPUPG: Attempting to intialize jet database (version %1!d!).\n",
  478. MSGERR_REGISTRY,L"DHCPUPG: Error reading parameters from registry: %1!d!.\n",
  479. MSGERR_LOADESE,L"DHCPUPG: Error failed to initialize ESE database: %1!d!.\n",
  480. MSGERR_LOAD500,L"DHCPUPG: Error failed to initialize Jet500 database: %1!d!.\n",
  481. MSGERR_LOAD200,L"DHCPUPG: Error failed to initialize Jet200 database: %1!d!.\n",
  482. MSGERR_GETCOL,L"DHCPUPG: Error retrieving column %2!d!: %1!d!.\n",
  483. MSGERR_GETMCOL,L"DHCPUPG: Error retrieving mcast column %2!d!: %1!d!.\n",
  484. MSGERR_SETINDEX,L"DHCPUPG: Error attempting to set the index for the database: %1!d!.\n",
  485. MSGERR_INVALIDIP,L"DHCPUPG: Invalid record -- IP address value is not of the right size.\n",
  486. MSGERR_INVALIDMASK,L"DHCPUPG: Invalid record -- Subnet Mask value is not of the right size.\n",
  487. MSGERR_INVALIDNAME,L"DHCPUPG: Invalid record -- Name value is not of the right size.\n",
  488. MSGERR_INVALIDINFO,L"DHCPUPG: Invalid record -- Machine Info value is not of the right size.\n",
  489. MSGERR_INVALIDEXPIRATION,L"DHCPUPG: Invalid record -- Lease value is not of the right size.\n",
  490. MSGERR_SCANCOUNT,L"DHCPUPG: Scanned %1!d! records.\n",
  491. MSGERR_SETMINDEX,L"DHCPUPG: Error attempting to set the index for the mcast table: %1!d!.\n",
  492. MSGERR_INVALIDMIP,L"DHCPUPG: Invalid mcast record -- IP address value is not of the right size.\n",
  493. MSGERR_INVALIDSCOPEID,L"DHCPUPG: Invalid mcast record -- ScopeId value is not of the right size.\n",
  494. MSGERR_INVALIDMEXPIRATION,L"DHCPUPG: Invalid mcast record -- Lease value is not of the right size.\n",
  495. MSGERR_INVALIDMSTART,L"DHCPUPG: Invalid mcast record -- LeaseStart value is not of the right size.\n",
  496. MSGERR_SCANMCOUNT,L"DHCPUPG: Scanned %1!d! mcast records.\n",
  497. MSGERR_CONVERT_FAILED,L"DHCPUPG: Failed to convert DHCP database to temporary format.\n",
  498. MSGERR_CONVERT_SUCCEEDED,L"DHCPUPG: Successfully converted DHCP database to temporary format.\n",
  499. MSGERR_CREATE_FILE_FAILED,L"DHCPUPG: Cannot create the destination temporary file: %1!d!.\n",
  500. MSGERR_OPENSCM,L"DHCPUPG: Unable to open the services control manager: %1!d!.\n",
  501. MSGERR_OPENSVC,L"DHCPUPG: Unable to open the DHCPServer service: %1!d!.\n",
  502. MSGERR_SVCQUERY,L"DHCPUPG: Unable to query the status of DHCPServer service: %1!d!.\n",
  503. MSGERR_SVCWAIT,L"DHCPUPG: DHCPServer service is in %1!d! state -- waiting for it to stop.\n",
  504. MSGERR_SVCCTRL,L"DHCPUPG: DHCPServer failed to stop: %1!d!.\n",
  505. MSGERR_SVCSTOP_SUCCESS,L"DHCPUPG: DHCPServer service has stopped successfully.\n",
  506. MSGERR_CREATE_MAP,L"DHCPUPG: Failed to create a mapping object for file: %1!d!.\n",
  507. MSGERR_CREATE_VIEW,L"DHCPUPG: Failed to create memory view for file: %1!d!.\n",
  508. MSGERR_SETVALUE,L"DHCPUPG: Failed to set the \"Version\" registry value: %1!d!.\n",
  509. MSGERR_DELETEFILE,L"DHCPUPG: Failed to delete the temporary file: %1!d!.\n",
  510. MSGERR_CHANGEPERMS,L"DHCPUPG: Failed to convert permissions on database: %1!d!.\n",
  511. 0xFFFFFFFF, 0
  512. };
  513. BOOL
  514. DebugLog(
  515. IN Winnt32DebugLevel Level,
  516. IN UINT MessageId,
  517. ...
  518. )
  519. {
  520. CHAR MessageA[5000];
  521. va_list arglist;
  522. DWORD Size, Written, i;
  523. LPWSTR Message;
  524. BOOL b;
  525. if( !hDebugLog ) return FALSE;
  526. if( Level > DebugLevel ) return TRUE;
  527. va_start(arglist,MessageId);
  528. Size = FormatMessageW(
  529. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  530. hInst, MessageId, 0, (LPWSTR)&Message, 0, &arglist );
  531. if( Size == 0 ) {
  532. for( i = 0; MessageMap[i].MessageId != 0xFFFFFFFF ; i ++ ) {
  533. if( MessageMap[i].MessageId == MessageId ) break;
  534. }
  535. if( MessageMap[i].MessageId == MessageId ) {
  536. Size = FormatMessageW(
  537. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  538. MessageMap[i].MessageStr, MessageId, 0,
  539. (LPWSTR)&Message, 0, &arglist );
  540. }
  541. }
  542. va_end(arglist);
  543. b = FALSE;
  544. if(Size) {
  545. Size = WideCharToMultiByte(
  546. CP_ACP, 0, Message, -1, MessageA, sizeof(MessageA),
  547. NULL, NULL );
  548. if( Size ) b = WriteFile(
  549. hDebugLog, MessageA, Size-1, &Written, NULL );
  550. LocalFree((HLOCAL)Message);
  551. }
  552. return b;
  553. }
  554. //
  555. // reading the database
  556. //
  557. enum {
  558. LoadJet200,
  559. LoadJet500,
  560. LoadJet97,
  561. };
  562. enum {
  563. RecordTypeDbEntry,
  564. RecordTypeMcastDbEntry,
  565. };
  566. //
  567. // database table and field names.
  568. //
  569. #define IPADDRESS_INDEX 0
  570. #define HARDWARE_ADDRESS_INDEX 1
  571. #define STATE_INDEX 2
  572. #define MACHINE_INFO_INDEX 3
  573. #define MACHINE_NAME_INDEX 4
  574. #define LEASE_TERMINATE_INDEX 5
  575. #define SUBNET_MASK_INDEX 6
  576. #define SERVER_IP_ADDRESS_INDEX 7
  577. #define SERVER_NAME_INDEX 8
  578. #define CLIENT_TYPE_INDEX 9
  579. #define MAX_INDEX 10
  580. #define LogErr printf
  581. #define LogInf printf
  582. #define LogError(A,B) if(Error)LogErr("DHCP: %s:%s:0x%lx\n",#A,#B,Error)
  583. #define LogErrorEx(A,B,C) if(Error)LogErr("DHCP: %s:%s:%s:0x%lx\n",#A,#B,#C,Error)
  584. #define LogInfo(A,B,C) LogInf("DHCP: " #A B, C)
  585. #define SAVE_BUF_SIZE (1004096L)
  586. #define SAVE_THRESHOLD (1000000L)
  587. //
  588. // Globals
  589. //
  590. DWORD LastError;
  591. DWORD JetVersion;
  592. CHAR DatabaseName[1024], DatabasePath[1024];
  593. HMODULE hJet;
  594. JET_INSTANCE JetInstance;
  595. JET_SESID JetSession;
  596. JET_DBID JetDb;
  597. JET_TABLEID JetTbl;
  598. PUCHAR SaveBuf;
  599. ULONG SaveBufSize;
  600. HANDLE hTextFile, hMapping;
  601. PVOID FileView;
  602. DWORD LoSize, HiSize;
  603. WCHAR Winnt32Path[MAX_PATH*2];
  604. CHAR System32Path[MAX_PATH*2];
  605. JET_ERR (JET_API *pJetSetCurrentIndex)(
  606. JET_SESID sesid,
  607. JET_TABLEID tableid,
  608. const char *szIndexName
  609. );
  610. JET_ERR (JET_API *pJetRetrieveColumn)(
  611. JET_SESID sesid,
  612. JET_TABLEID tableid,
  613. JET_COLUMNID columnid,
  614. void *pvData,
  615. unsigned long cbData,
  616. unsigned long *pcbActual,
  617. JET_GRBIT grbit,
  618. JET_RETINFO *pretinfo );
  619. JET_ERR (JET_API *pJetMove)(
  620. JET_SESID sesid,
  621. JET_TABLEID tableid,
  622. long cRow,
  623. JET_GRBIT grbit );
  624. JET_ERR (JET_API *pJetSetSystemParameter)(
  625. JET_INSTANCE *pinstance,
  626. JET_SESID sesid,
  627. unsigned long paramid,
  628. ULONG_PTR lParam,
  629. const char *sz );
  630. JET_ERR (JET_API *pJetTerm)( JET_INSTANCE instance );
  631. JET_ERR (JET_API *pJetTerm2)( JET_INSTANCE instance, JET_GRBIT grbit );
  632. JET_ERR (JET_API *pJetEndSession)( JET_SESID sesid, JET_GRBIT grbit );
  633. JET_ERR (JET_API *pJetBeginSession)(
  634. JET_INSTANCE instance,
  635. JET_SESID *psesid,
  636. const char *szUserName,
  637. const char *szPassword );
  638. JET_ERR (JET_API *pJetInit)( JET_INSTANCE *pinstance);
  639. JET_ERR (JET_API *pJetDetachDatabase)(
  640. JET_SESID sesid,
  641. const char *szFilename );
  642. JET_ERR (JET_API *pJetAttachDatabase)(
  643. JET_SESID sesid,
  644. const char *szFilename,
  645. JET_GRBIT grbit );
  646. JET_ERR (JET_API *pJetOpenDatabase)(
  647. JET_SESID sesid,
  648. const char *szFilename,
  649. const char *szConnect,
  650. JET_DBID *pdbid,
  651. JET_GRBIT grbit );
  652. JET_ERR (JET_API *pJetCloseDatabase)(
  653. JET_SESID sesid,
  654. JET_DBID dbid,
  655. JET_GRBIT grbit );
  656. JET_ERR (JET_API *pJetOpenTable)(
  657. JET_SESID sesid,
  658. JET_DBID dbid,
  659. const char *szTableName,
  660. const void *pvParameters,
  661. unsigned long cbParameters,
  662. JET_GRBIT grbit,
  663. JET_TABLEID *ptableid );
  664. JET_ERR (JET_API *pJetCloseTable)( JET_SESID sesid, JET_TABLEID tableid );
  665. JET_ERR (JET_API *pJetGetTableColumnInfo)(
  666. JET_SESID sesid,
  667. JET_TABLEID tableid,
  668. const char *szColumnName,
  669. void *pvResult,
  670. unsigned long cbMax,
  671. unsigned long InfoLevel );
  672. JET_ERR (JET_API *pJetGetIndexInfo)(
  673. JET_SESID sesid,
  674. JET_DBID dbid,
  675. const char *szTableName,
  676. const char *szIndexName,
  677. void *pvResult,
  678. unsigned long cbResult,
  679. unsigned long InfoLevel );
  680. #define DB_FUNC(F,I,S) \
  681. {#F, TEXT(#F), #F "@" #S, I, (FARPROC *)& p ## F }
  682. typedef struct _DB_FUNC_ENTRY {
  683. LPSTR FuncName;
  684. LPWSTR FuncNameW;
  685. LPSTR AltName;
  686. DWORD Index;
  687. FARPROC *FuncPtr;
  688. } DB_FUNC_ENTRY;
  689. DB_FUNC_ENTRY FuncTable[] = {
  690. DB_FUNC(JetSetCurrentIndex, 164, 12),
  691. DB_FUNC(JetRetrieveColumn, 157, 32),
  692. DB_FUNC(JetMove, 147, 16),
  693. DB_FUNC(JetSetSystemParameter, 165, 20),
  694. DB_FUNC(JetTerm, 167, 4),
  695. DB_FUNC(JetTerm2, 0, 8),
  696. DB_FUNC(JetEndSession, 124, 8),
  697. DB_FUNC(JetBeginSession, 104, 16),
  698. DB_FUNC(JetInit, 145, 4),
  699. DB_FUNC(JetDetachDatabase, 121, 8),
  700. DB_FUNC(JetAttachDatabase, 102, 12),
  701. DB_FUNC(JetOpenDatabase, 148, 20),
  702. DB_FUNC(JetOpenTable, 149, 28),
  703. DB_FUNC(JetGetTableColumnInfo, 137, 24),
  704. DB_FUNC(JetCloseTable,108, 8),
  705. DB_FUNC(JetCloseDatabase, 107, 12),
  706. DB_FUNC(JetGetIndexInfo, 131, 28),
  707. };
  708. #define JetSetCurrentIndex pJetSetCurrentIndex
  709. #define JetRetrieveColumn pJetRetrieveColumn
  710. #define JetMove pJetMove
  711. #define JetSetSystemParameter pJetSetSystemParameter
  712. #define JetTerm pJetTerm
  713. #define JetTerm2 pJetTerm2
  714. #define JetEndSession pJetEndSession
  715. #define JetBeginSession pJetBeginSession
  716. #define JetInit pJetInit
  717. #define JetDetachDatabase pJetDetachDatabase
  718. #define JetAttachDatabase pJetAttachDatabase
  719. #define JetOpenDatabase pJetOpenDatabase
  720. #define JetOpenTable pJetOpenTable
  721. #define JetGetTableColumnInfo pJetGetTableColumnInfo
  722. #define JetCloseTable pJetCloseTable
  723. #define JetCloseDatabase pJetCloseDatabase
  724. #define JetGetIndexInfo pJetGetIndexInfo
  725. typedef struct _TABLE_INFO {
  726. CHAR *ColName;
  727. JET_COLUMNID ColHandle;
  728. BOOL fPresent;
  729. JET_COLTYP ColType;
  730. } TABLE_INFO, *LPTABLE_INFO;
  731. #define IPADDRESS_STRING "IpAddress"
  732. #define HARDWARE_ADDRESS_STRING "HardwareAddress"
  733. #define STATE_STRING "State"
  734. #define MACHINE_INFO_STRING "MachineInformation"
  735. #define MACHINE_NAME_STRING "MachineName"
  736. #define LEASE_TERMINATE_STRING "LeaseTerminates"
  737. #define SUBNET_MASK_STRING "SubnetMask"
  738. #define SERVER_IP_ADDRESS_STRING "ServerIpAddress"
  739. #define SERVER_NAME_STRING "ServerName"
  740. #define CLIENT_TYPE "ClientType"
  741. static TABLE_INFO ClientTable[] = {
  742. { IPADDRESS_STRING , 0, 1, JET_coltypLong },
  743. { HARDWARE_ADDRESS_STRING , 0, 1, JET_coltypBinary },
  744. { STATE_STRING , 0, 1, JET_coltypUnsignedByte },
  745. { MACHINE_INFO_STRING , 0, 1, JET_coltypBinary }, // must modify MACHINE_INFO_SIZE if this changes
  746. { MACHINE_NAME_STRING , 0, 1, JET_coltypBinary },
  747. { LEASE_TERMINATE_STRING , 0, 1, JET_coltypCurrency },
  748. { SUBNET_MASK_STRING , 0, 1, JET_coltypLong },
  749. { SERVER_IP_ADDRESS_STRING, 0, 1, JET_coltypLong },
  750. { SERVER_NAME_STRING , 0, 1, JET_coltypBinary },
  751. { CLIENT_TYPE , 0, 1, JET_coltypUnsignedByte }
  752. };
  753. #define MCAST_CLIENT_TABLE_NAME "MCastClientTableVer3"
  754. #define MCAST_TBL_IPADDRESS_STR "MCastIpAddr"
  755. #define MCAST_TBL_CLIENT_ID_STR "MCastClientID"
  756. #define MCAST_TBL_CLIENT_INFO_STR "MCastClientInfo"
  757. #define MCAST_TBL_STATE_STR "MCastState"
  758. #define MCAST_TBL_FLAGS_STR "MCastFlags"
  759. #define MCAST_TBL_SCOPE_ID_STR "ScopeId"
  760. #define MCAST_TBL_LEASE_START_STR "MCastLeaseStart"
  761. #define MCAST_TBL_LEASE_END_STR "MCastLeaseEnd"
  762. #define MCAST_TBL_SERVER_IP_ADDRESS_STR "MCastServerIp"
  763. #define MCAST_TBL_SERVER_NAME_STR "MCastServerName"
  764. enum {
  765. MCAST_TBL_IPADDRESS,
  766. MCAST_TBL_CLIENT_ID,
  767. MCAST_TBL_CLIENT_INFO,
  768. MCAST_TBL_STATE,
  769. MCAST_TBL_FLAGS,
  770. MCAST_TBL_SCOPE_ID,
  771. MCAST_TBL_LEASE_START,
  772. MCAST_TBL_LEASE_END,
  773. MCAST_TBL_SERVER_IP_ADDRESS,
  774. MCAST_TBL_SERVER_NAME,
  775. MCAST_MAX_COLUMN
  776. };
  777. TABLE_INFO MadcapClientTable[] = {
  778. { MCAST_TBL_IPADDRESS_STR , 0, JET_coltypLongBinary },
  779. { MCAST_TBL_CLIENT_ID_STR , 0, JET_coltypBinary },
  780. { MCAST_TBL_CLIENT_INFO_STR , 0, JET_coltypLongBinary },
  781. { MCAST_TBL_STATE_STR , 0, JET_coltypUnsignedByte },
  782. { MCAST_TBL_FLAGS_STR , 0, JET_coltypLong },
  783. { MCAST_TBL_SCOPE_ID_STR , 0, JET_coltypBinary },
  784. { MCAST_TBL_LEASE_START_STR , 0, JET_coltypCurrency },
  785. { MCAST_TBL_LEASE_END_STR , 0, JET_coltypCurrency },
  786. { MCAST_TBL_SERVER_IP_ADDRESS_STR, 0, JET_coltypLongBinary },
  787. { MCAST_TBL_SERVER_NAME_STR, 0, JET_coltypBinary },
  788. };
  789. JET_TABLEID MadcapTbl;
  790. VOID static
  791. CleanupDatabase(
  792. VOID
  793. )
  794. {
  795. if( JetTbl != 0 ) {
  796. JetCloseTable( JetSession, JetTbl );
  797. JetTbl = 0;
  798. }
  799. if( MadcapTbl != 0 ) {
  800. JetCloseTable( JetSession, MadcapTbl );
  801. MadcapTbl = 0;
  802. }
  803. if( JetSession != 0 ) {
  804. JetEndSession( JetSession, 0 );
  805. JetSession = 0;
  806. }
  807. if( NULL != hJet ) {
  808. if( NULL != JetTerm2 ) {
  809. JetTerm2( JetInstance, JET_bitTermComplete );
  810. } else {
  811. JetTerm( JetInstance );
  812. }
  813. FreeLibrary( hJet ); hJet = NULL;
  814. }
  815. JetInstance = 0;
  816. }
  817. DWORD
  818. ReadString(
  819. IN HKEY hKey,
  820. IN LPSTR KeyName,
  821. IN LPSTR Buffer,
  822. IN ULONG BufSize
  823. )
  824. {
  825. DWORD Error, Size, Type;
  826. CHAR Str[1024];
  827. Size = sizeof(Str);
  828. Error = RegQueryValueExA(
  829. hKey, KeyName, NULL, &Type, (LPSTR)Str, &Size );
  830. if( NO_ERROR == Error ) {
  831. if( 0 == Size || 1 == Size ) Error = ERROR_NOT_FOUND;
  832. if( Type != REG_SZ && Type != REG_EXPAND_SZ && Type !=
  833. REG_MULTI_SZ ) Error = ERROR_BAD_FORMAT;
  834. }
  835. if( NO_ERROR != Error ) return Error;
  836. Size = ExpandEnvironmentStringsA( (LPSTR)Str, Buffer, BufSize );
  837. if( Size == 0 || Size > BufSize ) {
  838. Error = ERROR_META_EXPANSION_TOO_LONG;
  839. }
  840. if(Error) DebugLog(Winnt32LogError,MSGERR_EXPAND,KeyName);
  841. return Error;
  842. }
  843. DWORD
  844. ReadRegistry(
  845. VOID
  846. )
  847. {
  848. HKEY hKey;
  849. DWORD Error, Size;
  850. CHAR Str[1024];
  851. //
  852. // Open dhcp server parameters key
  853. //
  854. Error = RegOpenKeyEx(
  855. HKEY_LOCAL_MACHINE,
  856. TEXT("SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Parameters"),
  857. 0, KEY_READ, &hKey );
  858. if(Error)DebugLog(Winnt32LogError, MSGERR_OPENPARAMSKEY, Error );
  859. if( NO_ERROR != Error ) return Error;
  860. //
  861. // Read database details
  862. //
  863. do {
  864. Error = ReadString(
  865. hKey, "DatabasePath", (LPSTR)DatabasePath,
  866. sizeof(DatabasePath) );
  867. if(Error)DebugLog(Winnt32LogError,MSGERR_VALUE, L"DatabasePath", Error);
  868. if( NO_ERROR != Error ) break;
  869. Error = ReadString(
  870. hKey, "DatabaseName", (LPSTR)DatabaseName,
  871. sizeof(DatabaseName) );
  872. if(Error)DebugLog(Winnt32LogError,MSGERR_VALUE, L"DatabaseName", Error);
  873. if( NO_ERROR != Error ) break;
  874. Error = NO_ERROR;
  875. DebugLog(Winnt32LogInformation, MSGERR_GETDBPARAMS );
  876. } while( 0 );
  877. RegCloseKey( hKey );
  878. return Error;
  879. }
  880. DWORD
  881. LoadAndLinkRoutines(
  882. IN DWORD JetVersion
  883. )
  884. {
  885. DWORD Error, i;
  886. LPTSTR Module;
  887. LPSTR FuncName;
  888. Module = NULL;
  889. switch( JetVersion ) {
  890. case LoadJet97 : Module = TEXT("esent.dll"); break;
  891. case LoadJet500 : Module = TEXT("jet500.dll"); break;
  892. case LoadJet200 : Module = TEXT("jet.dll"); break;
  893. default: Module = TEXT("esent.dll"); break;
  894. }
  895. hJet = LoadLibrary( Module );
  896. if( NULL == hJet ) {
  897. Error = GetLastError();
  898. } else {
  899. Error = NO_ERROR;
  900. }
  901. if(Error)DebugLog(Winnt32LogInformation, MSGERR_LOAD, Error, Module );
  902. if( NO_ERROR != Error ) return Error;
  903. for( i = 0; i < sizeof(FuncTable)/sizeof(FuncTable[0]); i ++ ) {
  904. (*FuncTable[i].FuncPtr) = NULL;
  905. }
  906. for( i = 0; i < sizeof(FuncTable)/sizeof(FuncTable[0]); i ++ ) {
  907. if( LoadJet200 != JetVersion ) {
  908. FuncName = FuncTable[i].FuncName;
  909. } else {
  910. if( 0 == FuncTable[i].Index ) {
  911. (*FuncTable[i].FuncPtr) = NULL;
  912. continue;
  913. }
  914. FuncName = (LPSTR)ULongToPtr(FuncTable[i].Index);
  915. }
  916. Error = NO_ERROR;
  917. (*FuncTable[i].FuncPtr) = GetProcAddress(hJet, FuncName);
  918. if( NULL == FuncTable[i].FuncPtr ) {
  919. Error = GetLastError();
  920. if( LoadJet97 == JetVersion ) {
  921. (*FuncTable[i].FuncPtr) = GetProcAddress(
  922. hJet, FuncTable[i].AltName );
  923. if( NULL != FuncTable[i].FuncPtr ) continue;
  924. Error = GetLastError();
  925. }
  926. }
  927. if(Error) DebugLog(Winnt32LogError, MSGERR_GETPROCADDR, Error, FuncTable[i].FuncNameW );
  928. if( NO_ERROR != Error ) break;
  929. }
  930. //
  931. // if erred out, cleanup
  932. //
  933. if( NO_ERROR != Error ) {
  934. FreeLibrary( hJet );
  935. hJet = NULL;
  936. }
  937. return Error;
  938. }
  939. DWORD
  940. SetJetParams(
  941. IN DWORD JetVersion,
  942. IN LPSTR DbName,
  943. IN LPSTR DbPath
  944. )
  945. {
  946. DWORD Error, JetParam;
  947. CHAR Temp[2048];
  948. LPSTR DbSysFile = "\\system.mdb";
  949. LPSTR DbBaseName = "j50";
  950. Temp[ 0 ] = '\0';
  951. JetInstance = 0;
  952. if ( strlen( DbPath ) < 2048 )
  953. strcpy(Temp, DbPath);
  954. if( LoadJet200 == JetVersion ) {
  955. strcat(Temp, DbSysFile);
  956. JetParam = JET_paramSysDbPath_OLD;
  957. } else {
  958. strcat(Temp, "\\");
  959. if( LoadJet97 != JetVersion ) {
  960. JetParam = JET_paramSystemPath_OLD;
  961. } else {
  962. JetParam = JET_paramSystemPath;
  963. }
  964. }
  965. Error = JetSetSystemParameter(
  966. &JetInstance, (JET_SESID)0, JetParam, 0, Temp );
  967. if(Error)DebugLog(Winnt32LogError, MSGERR_SETDBPARAM, Error, JetParam );
  968. if( NO_ERROR != Error ) return Error;
  969. if( LoadJet200 != JetVersion ) {
  970. if( LoadJet97 != JetVersion ) {
  971. JetParam = JET_paramBaseName_OLD;
  972. } else {
  973. JetParam = JET_paramBaseName;
  974. }
  975. Error = JetSetSystemParameter(
  976. &JetInstance, (JET_SESID)0, JetParam, 0, DbBaseName );
  977. if(Error)DebugLog(Winnt32LogError, MSGERR_SETDBPARAM, Error, JetParam );
  978. if( NO_ERROR != Error ) return Error;
  979. }
  980. if( LoadJet200 != JetVersion ) {
  981. if( LoadJet97 == JetVersion ) {
  982. JetParam = JET_paramLogFileSize;
  983. } else {
  984. JetParam = JET_paramLogFileSize_OLD;
  985. }
  986. Error = JetSetSystemParameter(
  987. &JetInstance, (JET_SESID)0, JetParam, 1000, NULL );
  988. if(Error) DebugLog(Winnt32LogError, MSGERR_SETDBPARAM, Error,
  989. JetParam );
  990. if( NO_ERROR != Error ) return Error;
  991. }
  992. if( LoadJet200 != JetVersion ) {
  993. Error = JetSetSystemParameter(
  994. &JetInstance, (JET_SESID)0,
  995. JET_paramCheckFormatWhenOpenFail, 1, NULL );
  996. LogError(SetJetParams, OpenFail );
  997. JetParam = JET_paramCheckFormatWhenOpenFail;
  998. if(Error)DebugLog(Winnt32LogError, MSGERR_SETDBPARAM, Error, JetParam );
  999. if( NO_ERROR != Error ) return Error;
  1000. }
  1001. if( LoadJet200 != JetVersion ) {
  1002. if( LoadJet97 != JetVersion ) {
  1003. JetParam = JET_paramRecovery_OLD;
  1004. } else {
  1005. JetParam = JET_paramRecovery;
  1006. }
  1007. Error = JetSetSystemParameter(
  1008. &JetInstance, (JET_SESID)0, JetParam, 0, "on");
  1009. if(Error)DebugLog(Winnt32LogError, MSGERR_SETDBPARAM, Error, JetParam );
  1010. if( NO_ERROR != Error ) return Error;
  1011. }
  1012. //
  1013. // Note: Ideally, the log files should never exist. Even
  1014. // if the database is opened in readonly mode, they seem to
  1015. // exist. Not sure what else can be done
  1016. //
  1017. if( LoadJet97 == JetVersion ) {
  1018. JetParam = JET_paramLogFilePath;
  1019. } else {
  1020. JetParam = JET_paramLogFilePath_OLD;
  1021. }
  1022. strcpy(Temp, DbPath); strcat( Temp, "\\");
  1023. Error = JetSetSystemParameter(
  1024. &JetInstance, (JET_SESID)0, JetParam, 0, Temp );
  1025. if(Error)DebugLog(Winnt32LogError, MSGERR_SETDBPARAM, Error, JetParam );
  1026. return Error;
  1027. }
  1028. DWORD
  1029. OpenDatabase(
  1030. IN DWORD JetVersion,
  1031. IN LPSTR DbName,
  1032. IN LPSTR DbPath
  1033. )
  1034. {
  1035. LONG Error;
  1036. DWORD i;
  1037. CHAR FilePath[2048];
  1038. JET_INDEXLIST TmpIdxList;
  1039. JetSession = 0;
  1040. JetDb = 0;
  1041. JetTbl = 0;
  1042. MadcapTbl = 0;
  1043. FilePath[ 0 ] = '\0';
  1044. Error = JetInit( &JetInstance );
  1045. if(Error) DebugLog(Winnt32LogError, MSGERR_JETINIT, Error );
  1046. if( NO_ERROR != Error ) return Error;
  1047. Error = JetBeginSession(
  1048. JetInstance, &JetSession, "admin", "" );
  1049. if(Error) DebugLog(Winnt32LogError, MSGERR_JETBEGINSESSION, Error );
  1050. if( Error < 0 ) return Error;
  1051. if ( ( strlen( DbPath ) + strlen( DbName ) + 2 ) < 2048 )
  1052. {
  1053. strcpy(FilePath, DbPath );
  1054. strcat(FilePath, "\\" );
  1055. strcat(FilePath, DbName );
  1056. }
  1057. Error = JetDetachDatabase( JetSession, NULL );
  1058. if(Error) DebugLog(Winnt32LogError, MSGERR_JETDETACHDB, Error );
  1059. if( Error < 0 ) return Error;
  1060. Error = JetAttachDatabase( JetSession, FilePath, JET_bitDbRecoveryOff );
  1061. if(Error) DebugLog(Winnt32LogError, MSGERR_JETATTACHDB, Error );
  1062. if( Error < 0 ) return Error;
  1063. Error = JetOpenDatabase(
  1064. JetSession, FilePath, NULL, &JetDb,
  1065. JET_bitDbSingleExclusive | JET_bitDbReadOnly );
  1066. if(Error) DebugLog(Winnt32LogError, MSGERR_JETOPENDB, Error );
  1067. if( Error < 0 ) return Error;
  1068. Error = JetOpenTable(
  1069. JetSession, JetDb, (LPSTR)"ClientTable",
  1070. NULL, 0, JET_bitTableReadOnly,&JetTbl );
  1071. if(Error) DebugLog(Winnt32LogError, MSGERR_JETOPENTABLE, Error );
  1072. if( Error < 0 ) return Error;
  1073. for( i = 0; i < sizeof(ClientTable)/sizeof(ClientTable[0]); i ++ ) {
  1074. JET_COLUMNDEF ColDef;
  1075. Error = JetGetTableColumnInfo(
  1076. JetSession, JetTbl, ClientTable[i].ColName, &ColDef,
  1077. sizeof(ColDef), 0 );
  1078. if(Error && JET_errColumnNotFound != Error ) {
  1079. DebugLog(Winnt32LogError, MSGERR_JETGETCOL, Error );
  1080. }
  1081. if( Error < 0 ) {
  1082. if( JET_errColumnNotFound == Error ) {
  1083. ClientTable[i].fPresent = FALSE;
  1084. continue;
  1085. } else {
  1086. return Error;
  1087. }
  1088. }
  1089. if( ColDef.coltyp != ClientTable[i].ColType ) {
  1090. ASSERT( FALSE );
  1091. Error = ERROR_BAD_FORMAT;
  1092. return Error;
  1093. }
  1094. ClientTable[i].ColHandle = ColDef.columnid;
  1095. }
  1096. Error = JetOpenTable(
  1097. JetSession, JetDb, (LPSTR)"MCastClientTableVer3",
  1098. NULL, 0, JET_bitTableReadOnly, &MadcapTbl );
  1099. if( JET_errObjectNotFound == Error ) {
  1100. Error = NO_ERROR;
  1101. } else {
  1102. if(Error) DebugLog(Winnt32LogError, MSGERR_JETOPENMTABLE, Error );
  1103. if( Error < 0 ) return Error;
  1104. for( i = 0; i < sizeof(MadcapClientTable)/sizeof(MadcapClientTable[0]); i ++ ) {
  1105. JET_COLUMNDEF ColDef;
  1106. Error = JetGetTableColumnInfo(
  1107. JetSession, MadcapTbl, ClientTable[i].ColName, &ColDef,
  1108. sizeof(ColDef), 0 );
  1109. if(Error && Error != JET_errColumnNotFound) {
  1110. DebugLog(Winnt32LogError, MSGERR_JETGETMCOL, Error );
  1111. }
  1112. if( Error < 0 ) {
  1113. if( JET_errColumnNotFound == Error ) {
  1114. MadcapClientTable[i].fPresent = FALSE;
  1115. continue;
  1116. } else {
  1117. return Error;
  1118. }
  1119. }
  1120. if( ColDef.coltyp != MadcapClientTable[i].ColType ) {
  1121. ASSERT( FALSE );
  1122. Error = ERROR_BAD_FORMAT;
  1123. return Error;
  1124. }
  1125. MadcapClientTable[i].ColHandle = ColDef.columnid;
  1126. }
  1127. }
  1128. return NO_ERROR;
  1129. }
  1130. DWORD
  1131. LoadAndInitializeDatabase(
  1132. IN DWORD JetVersion,
  1133. IN LPSTR DbName,
  1134. IN LPSTR DbPath
  1135. )
  1136. {
  1137. DWORD Error;
  1138. //
  1139. // Attempt to load DLL and retrieve function pointers
  1140. //
  1141. DebugLog(Winnt32LogInformation, MSGERR_INITDB, JetVersion );
  1142. Error = LoadAndLinkRoutines( JetVersion );
  1143. if( NO_ERROR != Error ) return Error;
  1144. //
  1145. // set standard jet params
  1146. //
  1147. Error = SetJetParams( JetVersion, DbName, DbPath );
  1148. if( NO_ERROR != Error ) {
  1149. FreeLibrary( hJet ); hJet = NULL;
  1150. return Error;
  1151. }
  1152. //
  1153. // Attempt to open database
  1154. //
  1155. Error = OpenDatabase( JetVersion, DbName, DbPath );
  1156. if( NO_ERROR != Error ) {
  1157. CleanupDatabase();
  1158. return Error;
  1159. }
  1160. return NO_ERROR;
  1161. }
  1162. DWORD
  1163. LoadAndLinkSecurityRoutines(
  1164. OUT FARPROC *pGetInfo,
  1165. OUT FARPROC *pSetInfo
  1166. )
  1167. {
  1168. HMODULE hAdvapi32;
  1169. hAdvapi32 = GetModuleHandle(TEXT("ADVAPI32.DLL"));
  1170. if( NULL == hAdvapi32 ) return GetLastError();
  1171. (*pGetInfo) = GetProcAddress(hAdvapi32, "GetNamedSecurityInfoA");
  1172. if( NULL == *pGetInfo ) return GetLastError();
  1173. (*pSetInfo) = GetProcAddress(hAdvapi32, "SetNamedSecurityInfoA");
  1174. if( NULL == *pSetInfo ) return GetLastError();
  1175. return NO_ERROR;
  1176. }
  1177. DWORD
  1178. ConvertPermissionsOnDbFiles(
  1179. VOID
  1180. )
  1181. {
  1182. DWORD Error, dwVersion = GetVersion();
  1183. PSECURITY_DESCRIPTOR pSec;
  1184. PACL pAcl;
  1185. HANDLE hSearch = INVALID_HANDLE_VALUE;
  1186. WIN32_FIND_DATAA FileData;
  1187. CHAR FileName[1024];
  1188. FARPROC pGetInfo, pSetInfo;
  1189. CHAR DriversDirPath[MAX_PATH *2 +1];
  1190. DWORD PathLen = sizeof(DriversDirPath)-1;
  1191. //
  1192. // Check if version is atleast NT5.
  1193. //
  1194. dwVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
  1195. if( dwVersion < 5 ) return NO_ERROR;
  1196. //
  1197. // First get the requried function pointers..
  1198. //
  1199. Error = LoadAndLinkSecurityRoutines(
  1200. &pGetInfo, &pSetInfo );
  1201. if( NO_ERROR != Error ) return Error;
  1202. ZeroMemory(DriversDirPath, PathLen+1);
  1203. PathLen = ExpandEnvironmentStringsA(
  1204. "%SystemRoot%\\system32\\drivers", DriversDirPath, PathLen );
  1205. if( PathLen == 0 ) {
  1206. Error = GetLastError();
  1207. return Error;
  1208. }
  1209. pSec = NULL;
  1210. pAcl = NULL;
  1211. Error = (DWORD)pGetInfo(
  1212. "MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer",
  1213. SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, NULL, NULL,
  1214. &pAcl, NULL, &pSec );
  1215. if( NO_ERROR != Error ) return Error;
  1216. Error = (DWORD)pSetInfo(
  1217. DatabasePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
  1218. NULL, NULL, pAcl, NULL );
  1219. if( NO_ERROR != Error ) return Error;
  1220. strcpy(FileName, DatabasePath);
  1221. if( FileName[strlen(FileName)-1] != '\\' ) {
  1222. strcat(FileName, "\\");
  1223. }
  1224. strcat(FileName, DatabaseName);
  1225. Error = (DWORD)pSetInfo(
  1226. FileName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
  1227. NULL, NULL, pAcl, NULL );
  1228. if( NO_ERROR != Error ) goto Cleanup;
  1229. //
  1230. // Now for all files matching "*.log", repeat above operation
  1231. //
  1232. strcpy(FileName, DatabasePath);
  1233. if( FileName[strlen(FileName)-1] != '\\' ) {
  1234. strcat(FileName, "\\");
  1235. }
  1236. strcat(FileName, "*.*");
  1237. hSearch = FindFirstFileA( FileName, &FileData );
  1238. if( INVALID_HANDLE_VALUE == hSearch ) {
  1239. Error = GetLastError();
  1240. goto Cleanup;
  1241. }
  1242. do {
  1243. if( 0 != strcmp(FileData.cFileName, ".") &&
  1244. 0 != strcmp(FileData.cFileName, "..") ) {
  1245. strcpy(FileName, DatabasePath);
  1246. if( FileName[strlen(FileName)-1] != '\\' ) {
  1247. strcat(FileName, "\\");
  1248. }
  1249. strcat(FileName, FileData.cFileName);
  1250. Error = (DWORD)pSetInfo(
  1251. FileName, SE_FILE_OBJECT,
  1252. DACL_SECURITY_INFORMATION, NULL, NULL, pAcl, NULL );
  1253. if( NO_ERROR != Error ) break;
  1254. }
  1255. Error = FindNextFileA( hSearch, &FileData );
  1256. if( FALSE != Error ) Error = NO_ERROR;
  1257. else Error = GetLastError();
  1258. } while( NO_ERROR == Error );
  1259. FindClose( hSearch );
  1260. Cleanup:
  1261. LocalFree( pSec );
  1262. if( ERROR_FILE_NOT_FOUND == Error ) return NO_ERROR;
  1263. if( ERROR_NO_MORE_FILES == Error ) return NO_ERROR;
  1264. return Error;
  1265. }
  1266. DWORD
  1267. InitializeDatabase(
  1268. VOID
  1269. )
  1270. {
  1271. DWORD Error;
  1272. Error = ReadRegistry();
  1273. if(Error) DebugLog(Winnt32LogError, MSGERR_REGISTRY, Error );
  1274. if( NO_ERROR != Error ) return Error;
  1275. // Do not set the ACLs on %SystemRoot%\\system32\\dhcp
  1276. // Error = ConvertPermissionsOnDbFiles();
  1277. // if(Error) DebugLog(Winnt32LogError, MSGERR_CHANGEPERMS, Error );
  1278. // ignore error and try best effort
  1279. if( FALSE == SetCurrentDirectoryA(DatabasePath) ) {
  1280. Error = GetLastError();
  1281. if( ERROR_FILE_NOT_FOUND == Error ||
  1282. ERROR_PATH_NOT_FOUND == Error ) {
  1283. return ERROR_SERVICE_DOES_NOT_EXIST;
  1284. }
  1285. return Error;
  1286. }
  1287. Error = LoadAndInitializeDatabase(
  1288. LoadJet97, (LPSTR)DatabaseName, (LPSTR)DatabasePath );
  1289. if(Error) DebugLog( Winnt32LogInformation, MSGERR_LOADESE, Error );
  1290. if( NO_ERROR == Error ) return NO_ERROR;
  1291. Error = LoadAndInitializeDatabase(
  1292. LoadJet500, (LPSTR)DatabaseName, (LPSTR)DatabasePath );
  1293. if(Error) DebugLog( Winnt32LogInformation, MSGERR_LOAD500, Error );
  1294. if( NO_ERROR == Error ) return NO_ERROR;
  1295. Error = LoadAndInitializeDatabase(
  1296. LoadJet200, (LPSTR)DatabaseName, (LPSTR)DatabasePath );
  1297. if(Error) DebugLog( Winnt32LogInformation, MSGERR_LOAD200, Error );
  1298. return Error;
  1299. }
  1300. DWORD
  1301. GetColumnValue(
  1302. IN DWORD Index,
  1303. IN LPSTR Buffer,
  1304. IN OUT ULONG *BufSize
  1305. )
  1306. {
  1307. JET_ERR Error = NO_ERROR;
  1308. DWORD Size;
  1309. if( ClientTable[Index].fPresent == FALSE ) {
  1310. (*BufSize) = 0;
  1311. return NO_ERROR;
  1312. }
  1313. Error = JetRetrieveColumn(
  1314. JetSession, JetTbl, ClientTable[Index].ColHandle, Buffer,
  1315. *BufSize, &Size, 0, NULL );
  1316. if( JET_errColumnNotFound == Error ) {
  1317. Error = NO_ERROR;
  1318. Size = 0;
  1319. }
  1320. if(Error) DebugLog( Winnt32LogWarning, MSGERR_GETCOL, Error, Index);
  1321. if( Error < 0 ) return Error;
  1322. (*BufSize) = Size;
  1323. return NO_ERROR;
  1324. }
  1325. DWORD
  1326. GetMadcapColumnValue(
  1327. IN DWORD Index,
  1328. IN LPSTR Buffer,
  1329. IN OUT ULONG *BufSize
  1330. )
  1331. {
  1332. JET_ERR Error = NO_ERROR;
  1333. DWORD Size;
  1334. if( ClientTable[Index].fPresent == FALSE ) {
  1335. (*BufSize) = 0;
  1336. return NO_ERROR;
  1337. }
  1338. Error = JetRetrieveColumn(
  1339. JetSession, MadcapTbl,
  1340. MadcapClientTable[Index].ColHandle, Buffer,
  1341. *BufSize, &Size, 0, NULL );
  1342. if( JET_errColumnNotFound == Error ) {
  1343. Error = NO_ERROR;
  1344. Size = 0;
  1345. }
  1346. if(Error) DebugLog( Winnt32LogWarning, MSGERR_GETMCOL, Error, Index);
  1347. if( Error < 0 ) return Error;
  1348. (*BufSize) = Size;
  1349. return NO_ERROR;
  1350. }
  1351. #define CLIENT_TYPE_UNSPECIFIED 0x0 // for backward compatibility
  1352. #define CLIENT_TYPE_DHCP 0x1
  1353. #define CLIENT_TYPE_BOOTP 0x2
  1354. #define CLIENT_TYPE_BOTH ( CLIENT_TYPE_DHCP | CLIENT_TYPE_BOOTP )
  1355. #define ADDRESS_STATE_OFFERED 0
  1356. #define ADDRESS_STATE_ACTIVE 1
  1357. #define ADDRESS_STATE_DECLINED 2
  1358. #define ADDRESS_STATE_DOOM 3
  1359. #define ADDRESS_BIT_DELETED 0x80
  1360. #define ADDRESS_BIT_UNREGISTERED 0x40
  1361. #define ADDRESS_BIT_BOTH_REC 0x20
  1362. #define ADDRESS_BIT_CLEANUP 0x10
  1363. #define ADDRESS_BITS_MASK 0xF0
  1364. DWORD
  1365. AddRecord(
  1366. IN LPSTR Buffer,
  1367. IN ULONG BufSize
  1368. );
  1369. DWORD
  1370. AddScannedClient(
  1371. IN DWORD IpAddressNetOrder,
  1372. IN DWORD SubnetMaskNetOrder,
  1373. IN LPBYTE HwAddr,
  1374. IN ULONG HwLen,
  1375. IN LPWSTR MachineName,
  1376. IN LPWSTR MachineInfo,
  1377. IN ULONGLONG ExpirationFileTime,
  1378. IN BYTE State,
  1379. IN BYTE ClientType
  1380. )
  1381. {
  1382. DWORD i;
  1383. CHAR Buffer[1024];
  1384. ULONG Length, Size;
  1385. Length = 0;
  1386. Buffer[Length++] = (BYTE)RecordTypeDbEntry;
  1387. CopyMemory(
  1388. &Buffer[Length], (PVOID)&IpAddressNetOrder, sizeof(DWORD) );
  1389. Length += sizeof(DWORD);
  1390. CopyMemory(
  1391. &Buffer[Length], (PVOID)&SubnetMaskNetOrder, sizeof(DWORD) );
  1392. Length += sizeof(DWORD);
  1393. Buffer[Length++] = (BYTE)HwLen;
  1394. CopyMemory(&Buffer[Length], HwAddr, HwLen );
  1395. Length += HwLen;
  1396. if( NULL == MachineName || 0 == *MachineName ) Size = 0;
  1397. else Size = sizeof(WCHAR)*(1+wcslen(MachineName));
  1398. CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
  1399. Length += sizeof(DWORD);
  1400. CopyMemory(&Buffer[Length], (PVOID)MachineName, Size );
  1401. Length += Size;
  1402. if( NULL == MachineInfo || 0 == *MachineInfo ) Size = 0;
  1403. else Size = sizeof(WCHAR)*(1+wcslen(MachineInfo));
  1404. CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
  1405. Length += sizeof(DWORD);
  1406. CopyMemory(&Buffer[Length], (PVOID)MachineInfo, Size );
  1407. Length += Size;
  1408. CopyMemory(&Buffer[Length], (PVOID)&ExpirationFileTime, sizeof(ULONGLONG));
  1409. Length += sizeof(ULONGLONG);
  1410. Buffer[Length++] = State;
  1411. Buffer[Length++] = ClientType;
  1412. return AddRecord( Buffer, Length );
  1413. }
  1414. DWORD
  1415. AddScannedMadcapClient(
  1416. IN DWORD IpAddressNetOrder,
  1417. IN DWORD ScopeIdNetOrder,
  1418. IN LPBYTE ClientId,
  1419. IN ULONG HwLen,
  1420. IN LPWSTR MachineInfo,
  1421. IN ULONGLONG ExpirationFileTime,
  1422. IN ULONGLONG StartFileTime,
  1423. IN BYTE State
  1424. )
  1425. {
  1426. DWORD i;
  1427. CHAR Buffer[1024];
  1428. ULONG Length, Size;
  1429. Length = 0;
  1430. Buffer[Length++] = (BYTE)RecordTypeMcastDbEntry;
  1431. CopyMemory(
  1432. &Buffer[Length], (PVOID)&IpAddressNetOrder, sizeof(DWORD) );
  1433. Length += sizeof(DWORD);
  1434. CopyMemory(
  1435. &Buffer[Length], (PVOID)&ScopeIdNetOrder, sizeof(DWORD) );
  1436. Length += sizeof(DWORD);
  1437. Buffer[Length++] = (BYTE)HwLen;
  1438. CopyMemory(&Buffer[Length], ClientId, (BYTE)HwLen );
  1439. Length += (BYTE)HwLen;
  1440. if( NULL == MachineInfo || 0 == *MachineInfo ) Size = 0;
  1441. else Size = sizeof(WCHAR)*(1+wcslen(MachineInfo));
  1442. CopyMemory(&Buffer[Length], (PVOID)&Size, sizeof(DWORD));
  1443. Length += sizeof(DWORD);
  1444. CopyMemory(&Buffer[Length], (PVOID)MachineInfo, Size );
  1445. Length += Size;
  1446. CopyMemory(&Buffer[Length], (PVOID)&ExpirationFileTime, sizeof(ULONGLONG));
  1447. Length += sizeof(ULONGLONG);
  1448. CopyMemory(&Buffer[Length], (PVOID)&StartFileTime, sizeof(ULONGLONG));
  1449. Length += sizeof(ULONGLONG);
  1450. Buffer[Length++] = State;
  1451. return AddRecord( Buffer, Length );
  1452. }
  1453. DWORD static
  1454. ScanDatabase(
  1455. VOID
  1456. )
  1457. {
  1458. LONG Error;
  1459. DWORD Count;
  1460. Error = JetSetCurrentIndex(
  1461. JetSession, JetTbl, NULL );
  1462. if( Error ) DebugLog(Winnt32LogError, MSGERR_SETINDEX, Error );
  1463. if( Error < 0 ) return Error;
  1464. Error = JetMove( JetSession, JetTbl, JET_MoveFirst, 0 );
  1465. for( Count = 0 ; Error >= 0 ; Count ++,
  1466. Error = JetMove(JetSession, JetTbl, JET_MoveNext, 0) ) {
  1467. DWORD IpAddress, SubnetMask, Size, HwLen;
  1468. FILETIME Expiration;
  1469. CHAR HwAddress[256];
  1470. WCHAR MachineName[300], MachineInfo[300];
  1471. BYTE Type, State;
  1472. //
  1473. // Get current client's info.
  1474. //
  1475. Size = sizeof(IpAddress);
  1476. Error = GetColumnValue(
  1477. IPADDRESS_INDEX, (PVOID)&IpAddress, &Size );
  1478. if( NO_ERROR != Error ) break;
  1479. if( Size != sizeof(IpAddress) ) {
  1480. DebugLog(Winnt32LogError, MSGERR_INVALIDIP );
  1481. continue;
  1482. }
  1483. Size = sizeof(SubnetMask);
  1484. Error = GetColumnValue(
  1485. SUBNET_MASK_INDEX, (PVOID)&SubnetMask, &Size );
  1486. if( NO_ERROR != Error ) break;
  1487. if( Size != sizeof(SubnetMask) ) {
  1488. DebugLog(Winnt32LogError, MSGERR_INVALIDMASK );
  1489. continue;
  1490. }
  1491. HwLen = sizeof(HwAddress);
  1492. Error = GetColumnValue(
  1493. HARDWARE_ADDRESS_INDEX, (PVOID)HwAddress, &HwLen );
  1494. if( NO_ERROR != Error ) break;
  1495. Size = sizeof(MachineName);
  1496. Error = GetColumnValue(
  1497. MACHINE_NAME_INDEX, (PVOID)MachineName, &Size );
  1498. if( NO_ERROR != Error ) break;
  1499. if( (Size % 2) != 0 ) {
  1500. DebugLog(Winnt32LogError, MSGERR_INVALIDNAME );
  1501. continue;
  1502. }
  1503. MachineName[Size/2] = L'\0';
  1504. Size = sizeof(MachineInfo);
  1505. Error = GetColumnValue(
  1506. MACHINE_INFO_INDEX, (PVOID)MachineInfo, &Size );
  1507. if( NO_ERROR != Error ) break;
  1508. if( (Size % 2) != 0 ) {
  1509. DebugLog(Winnt32LogError, MSGERR_INVALIDINFO );
  1510. continue;
  1511. }
  1512. MachineInfo[Size/2] = L'\0';
  1513. Size = sizeof(Expiration);
  1514. Error = GetColumnValue(
  1515. LEASE_TERMINATE_INDEX, (PVOID)&Expiration, &Size );
  1516. if( NO_ERROR != Error ) break;
  1517. if( Size != sizeof(Expiration) ) {
  1518. DebugLog(Winnt32LogError, MSGERR_INVALIDEXPIRATION );
  1519. Error = ERROR_INVALID_DATA;
  1520. break;
  1521. }
  1522. Size = sizeof(Type);
  1523. Error = GetColumnValue(
  1524. CLIENT_TYPE_INDEX, (PVOID)&Type, &Size );
  1525. if( NO_ERROR != Error || 0 == Size ) {
  1526. Type = CLIENT_TYPE_DHCP;
  1527. }
  1528. Size = sizeof(State);
  1529. Error = GetColumnValue(
  1530. STATE_INDEX, (PVOID)&State, &Size );
  1531. if( NO_ERROR != Error || 0 == Size ) {
  1532. State = ADDRESS_STATE_ACTIVE;
  1533. }
  1534. if( ADDRESS_STATE_OFFERED == State ) {
  1535. continue;
  1536. }
  1537. //
  1538. // Try to add the client
  1539. //
  1540. Error = AddScannedClient(
  1541. ByteSwap(IpAddress), ByteSwap(SubnetMask), HwAddress, HwLen,
  1542. MachineName, MachineInfo, *(PULONGLONG)&Expiration,
  1543. State, Type );
  1544. if( NO_ERROR != Error ) break;
  1545. }
  1546. DebugLog( Winnt32LogInformation, MSGERR_SCANCOUNT, Count );
  1547. if( JET_errNoCurrentRecord == Error ) return NO_ERROR;
  1548. if( Error < 0 ) return Error;
  1549. return NO_ERROR;
  1550. }
  1551. DWORD
  1552. ScanMadcapDatabase(
  1553. VOID
  1554. )
  1555. {
  1556. LONG Error;
  1557. DWORD Count;
  1558. if( 0 == MadcapTbl ) return NO_ERROR;
  1559. Error = JetSetCurrentIndex(
  1560. JetSession, MadcapTbl, NULL );
  1561. if( Error ) DebugLog(Winnt32LogError, MSGERR_SETMINDEX, Error );
  1562. if( Error < 0 ) return Error;
  1563. Error = JetMove( JetSession, MadcapTbl, JET_MoveFirst, 0 );
  1564. for( Count = 0 ; Error >= 0 ; Count ++,
  1565. Error = JetMove(JetSession, MadcapTbl, JET_MoveNext, 0) ) {
  1566. DWORD IpAddress, ScopeId, Size, HwLen;
  1567. FILETIME Expiration, Start;
  1568. CHAR ClientId[300];
  1569. WCHAR ClientInfo[300], MachineInfo[300];
  1570. BYTE State;
  1571. //
  1572. // Get current client's info.
  1573. //
  1574. Size = sizeof(IpAddress);
  1575. Error = GetMadcapColumnValue(
  1576. MCAST_TBL_IPADDRESS, (PVOID)&IpAddress, &Size );
  1577. if( NO_ERROR != Error ) break;
  1578. if( Size != sizeof(IpAddress) ) {
  1579. DebugLog(Winnt32LogError, MSGERR_INVALIDMIP );
  1580. continue;
  1581. }
  1582. Size = sizeof(ScopeId);
  1583. Error = GetMadcapColumnValue(
  1584. MCAST_TBL_SCOPE_ID, (PVOID)&ScopeId, &Size );
  1585. if( NO_ERROR != Error ) break;
  1586. if( Size != sizeof( ScopeId ) ) {
  1587. DebugLog(Winnt32LogError, MSGERR_INVALIDSCOPEID);
  1588. continue;
  1589. }
  1590. HwLen = sizeof(ClientId);
  1591. Error = GetMadcapColumnValue(
  1592. MCAST_TBL_CLIENT_ID, (PVOID)ClientId, &HwLen );
  1593. if( NO_ERROR != Error ) break;
  1594. Size = sizeof(MachineInfo);
  1595. Error = GetMadcapColumnValue(
  1596. MCAST_TBL_CLIENT_INFO, (PVOID)MachineInfo, &Size );
  1597. if( NO_ERROR != Error ) break;
  1598. if( (Size % 2) != 0 ) {
  1599. DebugLog(Winnt32LogError, MSGERR_INVALIDINFO );
  1600. continue;
  1601. }
  1602. MachineInfo[Size/2] = L'\0';
  1603. Size = sizeof(Expiration);
  1604. Error = GetMadcapColumnValue(
  1605. MCAST_TBL_LEASE_END, (PVOID)&Expiration, &Size );
  1606. if( NO_ERROR != Error ) break;
  1607. if( Size != sizeof(Expiration) ) {
  1608. DebugLog(Winnt32LogError, MSGERR_INVALIDMEXPIRATION );
  1609. Error = ERROR_INVALID_DATA;
  1610. break;
  1611. }
  1612. Size = sizeof(Start);
  1613. Error = GetMadcapColumnValue(
  1614. MCAST_TBL_LEASE_START, (PVOID)&Start, &Size );
  1615. LogError( ScanMadcapDatabase, GetLeaseExpiration );
  1616. if( NO_ERROR != Error ) break;
  1617. if( Size != sizeof(Start) ) {
  1618. DebugLog(Winnt32LogError, MSGERR_INVALIDMSTART );
  1619. Error = ERROR_INVALID_DATA;
  1620. break;
  1621. }
  1622. Size = sizeof(State);
  1623. Error = GetMadcapColumnValue(
  1624. MCAST_TBL_STATE, (PVOID)&State, &Size );
  1625. if( NO_ERROR != Error ) break;
  1626. //
  1627. // Try to add the client
  1628. //
  1629. Error = AddScannedMadcapClient(
  1630. ByteSwap(IpAddress), ByteSwap(ScopeId), ClientId, HwLen,
  1631. MachineInfo, *(PULONGLONG)&Expiration,
  1632. *(PULONGLONG)&Start, State );
  1633. if( NO_ERROR != Error ) break;
  1634. }
  1635. DebugLog( Winnt32LogInformation, MSGERR_SCANMCOUNT, Count );
  1636. if( JET_errNoCurrentRecord == Error ) return NO_ERROR;
  1637. if( Error < 0 ) return Error;
  1638. return NO_ERROR;
  1639. }
  1640. DWORD
  1641. DumpData(
  1642. IN LPSTR Buffer,
  1643. IN ULONG BufSize
  1644. )
  1645. {
  1646. return NO_ERROR;
  1647. }
  1648. DWORD
  1649. AddRecord(
  1650. IN LPSTR Buffer,
  1651. IN ULONG BufSize
  1652. )
  1653. {
  1654. DWORD Written, Error = NO_ERROR;
  1655. if( NULL != Buffer ) {
  1656. CopyMemory(&SaveBuf[SaveBufSize], (PVOID)&BufSize, sizeof(DWORD));
  1657. CopyMemory(&SaveBuf[SaveBufSize+sizeof(DWORD)], Buffer, BufSize );
  1658. } else {
  1659. if( 0 == SaveBufSize ) return NO_ERROR;
  1660. if( FALSE == WriteFile(
  1661. hTextFile, SaveBuf, SaveBufSize, &Written, NULL ) ) {
  1662. return GetLastError();
  1663. }
  1664. if( Written != SaveBufSize ) {
  1665. ASSERT(FALSE);
  1666. return ERROR_CAN_NOT_COMPLETE;
  1667. }
  1668. return NO_ERROR;
  1669. }
  1670. if( SaveBufSize <= SAVE_THRESHOLD ) {
  1671. SaveBufSize += BufSize + sizeof(DWORD);
  1672. } else {
  1673. if( FALSE == WriteFile(
  1674. hTextFile, SaveBuf, SaveBufSize + BufSize + sizeof(DWORD),
  1675. &Written, NULL )) {
  1676. return GetLastError();
  1677. }
  1678. if( Written != SaveBufSize + BufSize + sizeof(DWORD) ) {
  1679. ASSERT(FALSE);
  1680. return ERROR_CAN_NOT_COMPLETE;
  1681. }
  1682. SaveBufSize = 0;
  1683. }
  1684. return Error;
  1685. }
  1686. DWORD
  1687. OpenTextFile(
  1688. BOOL fRead
  1689. )
  1690. {
  1691. CHAR FileName[4096];
  1692. DWORD Error, Flags;
  1693. strcpy(FileName, DatabasePath);
  1694. if( DatabasePath[strlen(DatabasePath)-1] != '\\' ) {
  1695. strcat(FileName, "\\dhcpdb.txt" );
  1696. } else {
  1697. strcat(FileName, "dhcpdb.txt");
  1698. }
  1699. Flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN;
  1700. hTextFile = CreateFileA(
  1701. FileName, GENERIC_READ | GENERIC_WRITE | DELETE,
  1702. FILE_SHARE_READ, NULL,
  1703. fRead ? OPEN_EXISTING : CREATE_ALWAYS,
  1704. Flags, NULL );
  1705. if( hTextFile == INVALID_HANDLE_VALUE ) {
  1706. hTextFile = NULL;
  1707. Error = GetLastError();
  1708. if( !fRead || ERROR_FILE_NOT_FOUND != Error ) {
  1709. DebugLog( Winnt32LogError, MSGERR_CREATE_FILE_FAILED, Error);
  1710. }
  1711. return Error;
  1712. }
  1713. if( !fRead ) return NO_ERROR;
  1714. LoSize = GetFileSize( hTextFile, &HiSize );
  1715. if( -1 == LoSize && NO_ERROR != GetLastError() ) {
  1716. return GetLastError();
  1717. }
  1718. if( LoSize == 0 && HiSize == 0 ) return NO_ERROR;
  1719. hMapping = CreateFileMapping(
  1720. hTextFile, NULL, PAGE_READONLY | SEC_COMMIT, HiSize, LoSize,
  1721. NULL );
  1722. if( NULL == hMapping ) {
  1723. Error = GetLastError();
  1724. DebugLog( Winnt32LogError, MSGERR_CREATE_MAP, Error );
  1725. return Error;
  1726. }
  1727. FileView = MapViewOfFile(
  1728. hMapping, FILE_MAP_READ, 0, 0, 0 );
  1729. if( NULL == FileView ) {
  1730. Error = GetLastError();
  1731. DebugLog( Winnt32LogError, MSGERR_CREATE_VIEW, Error );
  1732. return Error;
  1733. }
  1734. return NO_ERROR;
  1735. }
  1736. DWORD
  1737. StopDhcpService(
  1738. VOID
  1739. )
  1740. {
  1741. SC_HANDLE hSc, hSvc;
  1742. DWORD Error;
  1743. Error = NO_ERROR;
  1744. hSc = NULL;
  1745. hSvc = NULL;
  1746. do {
  1747. hSc = OpenSCManager(
  1748. NULL, NULL, SC_MANAGER_CONNECT | GENERIC_WRITE | GENERIC_WRITE );
  1749. if( NULL == hSc ) {
  1750. Error = GetLastError();
  1751. DebugLog( Winnt32LogError, MSGERR_OPENSCM, Error );
  1752. break;
  1753. }
  1754. hSvc = OpenService(
  1755. hSc, TEXT("DHCPServer"), SERVICE_STOP| SERVICE_QUERY_STATUS );
  1756. if( NULL == hSvc ) {
  1757. Error = GetLastError();
  1758. DebugLog( Winnt32LogError, MSGERR_OPENSVC, Error );
  1759. break;
  1760. }
  1761. while( NO_ERROR == Error ) {
  1762. SERVICE_STATUS Status;
  1763. if( FALSE == QueryServiceStatus( hSvc, &Status ) ) {
  1764. Error = GetLastError();
  1765. DebugLog( Winnt32LogError, MSGERR_SVCQUERY, Error );
  1766. break;
  1767. }
  1768. if( Status.dwCurrentState == SERVICE_STOPPED ) break;
  1769. if( Status.dwCurrentState != SERVICE_RUNNING &&
  1770. Status.dwCurrentState != SERVICE_PAUSED ) {
  1771. DebugLog( Winnt32LogInformation, MSGERR_SVCWAIT,
  1772. Status.dwCurrentState );
  1773. if( Status.dwWaitHint < 1000 ) {
  1774. Status.dwWaitHint = 1000;
  1775. }
  1776. Sleep(Status.dwWaitHint);
  1777. } else {
  1778. Error = ControlService(
  1779. hSvc, SERVICE_CONTROL_STOP, &Status );
  1780. if( FALSE != Error ) Error = NO_ERROR;
  1781. else {
  1782. Error = GetLastError();
  1783. DebugLog( Winnt32LogError, MSGERR_SVCCTRL, Error );
  1784. break;
  1785. }
  1786. }
  1787. }
  1788. } while( 0 );
  1789. if( NO_ERROR == Error ) {
  1790. DebugLog( Winnt32LogInformation, MSGERR_SVCSTOP_SUCCESS );
  1791. }
  1792. if( NULL != hSvc ) CloseServiceHandle( hSvc );
  1793. if( NULL != hSc ) CloseServiceHandle( hSc );
  1794. return Error;
  1795. }
  1796. BOOL
  1797. UpgradeNotNeeded(
  1798. VOID
  1799. )
  1800. {
  1801. HKEY hKey;
  1802. DWORD Error, Type, Value, Size;
  1803. Error = RegOpenKeyEx(
  1804. HKEY_LOCAL_MACHINE,
  1805. TEXT("SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Parameters"),
  1806. 0, KEY_READ, &hKey );
  1807. if( NO_ERROR != Error ) return FALSE;
  1808. Type = REG_DWORD; Value = 0; Size = sizeof(Value);
  1809. Error = RegQueryValueEx(
  1810. hKey, TEXT("Version"), NULL, &Type, (PVOID)&Value, &Size );
  1811. RegCloseKey( hKey );
  1812. //
  1813. // if this value is not present, then upgrade is needed
  1814. //
  1815. return (Error == NO_ERROR );
  1816. }
  1817. DWORD __stdcall
  1818. DhcpUpgConvertDhcpDbToTemp(
  1819. VOID
  1820. )
  1821. {
  1822. DWORD Error;
  1823. DWORD clusState;
  1824. DWORD Error1 = ERROR_SUCCESS;
  1825. GetClusterStateFn pGetClusterStateFn = NULL;
  1826. HINSTANCE hLib;
  1827. LastError = NO_ERROR;
  1828. if( UpgradeNotNeeded() ) return NO_ERROR;
  1829. Error = GetCurrentDirectoryW(
  1830. sizeof(Winnt32Path)/sizeof(WCHAR), Winnt32Path );
  1831. if( 0 != Error ) {
  1832. Error = NO_ERROR;
  1833. } else {
  1834. Error = GetLastError();
  1835. return Error;
  1836. }
  1837. SaveBuf = LocalAlloc(LPTR, SAVE_BUF_SIZE);
  1838. if( NULL == SaveBuf ) {
  1839. return GetLastError();
  1840. }
  1841. SaveBufSize = 0;
  1842. Error = NO_ERROR;
  1843. StartDebug();
  1844. DebugLog( Winnt32LogInformation, MSGERR_STARTLOG );
  1845. do {
  1846. Error = StopDhcpService();
  1847. if( NO_ERROR != Error ) break;
  1848. Error = InitializeDatabase();
  1849. if( NO_ERROR != Error ) break;
  1850. Error = OpenTextFile(FALSE);
  1851. if( NO_ERROR != Error ) break;
  1852. Error = ScanDatabase();
  1853. if( NO_ERROR != Error ) break;
  1854. Error = ScanMadcapDatabase();
  1855. if( NO_ERROR != Error ) break;
  1856. Error = AddRecord( NULL, 0 );
  1857. } while( 0 );
  1858. if( NULL != SaveBuf ) {
  1859. LocalFree( SaveBuf );
  1860. SaveBuf = 0;
  1861. }
  1862. CleanupDatabase();
  1863. if( NULL != hTextFile ) CloseHandle( hTextFile );
  1864. hTextFile = NULL;
  1865. //
  1866. // if the error code is ERROR_BUSY, it could be a cluster node
  1867. // that doesnt have access to the db. Check if this is the case.
  1868. //
  1869. if ( ERROR_BUSY == Error )
  1870. {
  1871. hLib = LoadLibrary( L"clusapi.dll" );
  1872. if ( hLib != NULL )
  1873. {
  1874. pGetClusterStateFn = (GetClusterStateFn)GetProcAddress( hLib, "GetNodeClusterState" );
  1875. }
  1876. if ( pGetClusterStateFn != NULL )
  1877. {
  1878. Error1 = pGetClusterStateFn( NULL, &clusState );
  1879. if ( Error1 == ERROR_SUCCESS )
  1880. {
  1881. if ( ( clusState & ClusterStateNotRunning ) ||
  1882. ( clusState & ClusterStateRunning ) )
  1883. {
  1884. //
  1885. // the error code remains the same if the above
  1886. // condition is not met.
  1887. //
  1888. Error = ERROR_SUCCESS;
  1889. }
  1890. }
  1891. }
  1892. if ( hLib != NULL )
  1893. {
  1894. FreeLibrary( hLib );
  1895. }
  1896. }
  1897. //
  1898. // If the service never existed, not much to do
  1899. //
  1900. if( ERROR_SERVICE_DOES_NOT_EXIST == Error ) Error = NO_ERROR;
  1901. if( NO_ERROR != Error ) {
  1902. DebugLog( Winnt32LogError, MSGERR_CONVERT_FAILED, Error );
  1903. } else {
  1904. DebugLog( Winnt32LogInformation, MSGERR_CONVERT_SUCCEEDED );
  1905. }
  1906. CloseDebugLog();
  1907. if( FALSE == SetCurrentDirectoryW(Winnt32Path) ) {
  1908. if( NO_ERROR == Error ) Error = GetLastError();
  1909. }
  1910. LastError = Error;
  1911. return NO_ERROR;
  1912. }
  1913. VOID
  1914. DeleteDatabaseTempFile(
  1915. VOID
  1916. )
  1917. {
  1918. CHAR FileName[4096];
  1919. DWORD Error;
  1920. //
  1921. // Attempt to delete the temporary database stuff
  1922. //
  1923. strcpy(FileName, DatabasePath);
  1924. if( DatabasePath[strlen(DatabasePath)-1] != '\\' ) {
  1925. strcat(FileName, "\\dhcpdb.txt" );
  1926. } else {
  1927. strcat(FileName, "dhcpdb.txt");
  1928. }
  1929. if( FALSE == DeleteFileA( FileName ) ) {
  1930. Error = GetLastError();
  1931. DebugLog(
  1932. Winnt32LogError, MSGERR_DELETEFILE, Error );
  1933. }
  1934. }
  1935. VOID
  1936. FixRegistryAndDeleteFiles(
  1937. VOID
  1938. )
  1939. {
  1940. DWORD Error;
  1941. HKEY hKey;
  1942. //
  1943. // Attempt to write the version key
  1944. //
  1945. Error = RegOpenKeyEx(
  1946. HKEY_LOCAL_MACHINE,
  1947. TEXT("SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Parameters"),
  1948. 0, KEY_WRITE, &hKey );
  1949. if( NO_ERROR != Error ) {
  1950. DebugLog(
  1951. Winnt32LogError, MSGERR_OPENPARAMSKEY, Error );
  1952. } else {
  1953. DWORD Version = 0, Size = sizeof(Version);
  1954. Error = RegSetValueEx(
  1955. hKey, TEXT("Version"), 0, REG_DWORD, (PVOID)&Version,
  1956. Size );
  1957. if( NO_ERROR != Error ) {
  1958. DebugLog(
  1959. Winnt32LogError, MSGERR_SETVALUE, Error );
  1960. }
  1961. RegCloseKey( hKey );
  1962. }
  1963. DeleteDatabaseTempFile();
  1964. }
  1965. DWORD __stdcall PrintRecord(
  1966. IN PDHCP_RECORD Recx
  1967. )
  1968. {
  1969. DWORD i;
  1970. DHCP_RECORD Rec = *Recx;
  1971. if( Rec.fMcast ) {
  1972. printf("Mcast Record\n" );
  1973. printf("Address: %s\n", IpAddressToString(
  1974. Rec.Info.Mcast.Address ));
  1975. printf("ScopeId: %s\n", IpAddressToString(
  1976. Rec.Info.Mcast.ScopeId ));
  1977. printf("ClientId:");
  1978. for( i = 0 ; i < (DWORD)Rec.Info.Mcast.HwLen; i ++ ) {
  1979. printf(" %02X", Rec.Info.Mcast.ClientId[i]);
  1980. }
  1981. printf("\nState = %02X\n", Rec.Info.Mcast.State);
  1982. } else {
  1983. printf("DHCP Record\n" );
  1984. printf("Address: %s\n", IpAddressToString(
  1985. Rec.Info.Dhcp.Address ));
  1986. printf("Mask: %s\n", IpAddressToString(
  1987. Rec.Info.Dhcp.Mask ));
  1988. printf("ClientId:");
  1989. for( i = 0 ; i < (DWORD)Rec.Info.Dhcp.HwLen; i ++ ) {
  1990. printf(" %02X", Rec.Info.Dhcp.HwAddr[i]);
  1991. }
  1992. printf("\nState = %02X\n", Rec.Info.Dhcp.State);
  1993. printf("\nType = %02X\n", Rec.Info.Dhcp.Type);
  1994. if( Rec.Info.Dhcp.Name ) {
  1995. printf("Name = %ws\n", Rec.Info.Dhcp.Name );
  1996. }
  1997. if( Rec.Info.Dhcp.Info ) {
  1998. printf("Comment = %ws\n", Rec.Info.Dhcp.Info );
  1999. }
  2000. }
  2001. return NO_ERROR;
  2002. }
  2003. DWORD
  2004. ProcessDbEntries(
  2005. IN LPSTR Buffer,
  2006. IN ULONG BufSize,
  2007. IN DHCP_ADD_RECORD_ROUTINE AddRec
  2008. )
  2009. {
  2010. DWORD Size, ThisSize, DbEntry;
  2011. LPSTR Buf;
  2012. DWORD Address, i, Error;
  2013. FILETIME Time;
  2014. DHCP_RECORD Rec;
  2015. Error = NO_ERROR;
  2016. while( BufSize > sizeof(DWORD) ) {
  2017. CopyMemory(&ThisSize, Buffer, sizeof(DWORD));
  2018. Buffer += sizeof(DWORD);
  2019. BufSize -= sizeof(DWORD);
  2020. if( ThisSize > BufSize ) return ERROR_INVALID_DATA;
  2021. if( ThisSize == 0 ) continue;
  2022. DbEntry = *Buffer;
  2023. Buf = Buffer+1;
  2024. Buffer += ThisSize;
  2025. BufSize -= ThisSize;
  2026. ZeroMemory( &Rec, sizeof(Rec));
  2027. switch(DbEntry) {
  2028. default :
  2029. return ERROR_INVALID_DATA;
  2030. case RecordTypeDbEntry :
  2031. Rec.fMcast = FALSE;
  2032. CopyMemory( &Rec.Info.Dhcp.Address, Buf, sizeof(DWORD));
  2033. Buf += sizeof(DWORD);
  2034. CopyMemory( &Rec.Info.Dhcp.Mask, Buf, sizeof(DWORD));
  2035. Buf += sizeof(DWORD);
  2036. Size = Rec.Info.Dhcp.HwLen = *Buf++;
  2037. Rec.Info.Dhcp.HwAddr = Buf;
  2038. Buf += Size;
  2039. CopyMemory(&Size, Buf, sizeof(DWORD));
  2040. Buf += sizeof(DWORD);
  2041. if( Size ) {
  2042. Rec.Info.Dhcp.Name = (PVOID)Buf;
  2043. Buf += Size;
  2044. }
  2045. CopyMemory(&Size, Buf, sizeof(DWORD));
  2046. Buf += sizeof(DWORD);
  2047. if( Size ) {
  2048. Rec.Info.Dhcp.Info = (PVOID)Buf;
  2049. Buf += Size;
  2050. }
  2051. CopyMemory(&Rec.Info.Dhcp.ExpTime, Buf, sizeof(FILETIME));
  2052. Buf += sizeof(FILETIME);
  2053. Rec.Info.Dhcp.State = Buf[0];
  2054. Rec.Info.Dhcp.Type = Buf[1];
  2055. Error = AddRec( &Rec );
  2056. break;
  2057. case RecordTypeMcastDbEntry :
  2058. Rec.fMcast = TRUE;
  2059. CopyMemory( &Rec.Info.Mcast.Address, Buf, sizeof(DWORD));
  2060. Buf += sizeof(DWORD);
  2061. CopyMemory( &Rec.Info.Mcast.ScopeId, Buf, sizeof(DWORD));
  2062. Buf += sizeof(DWORD);
  2063. Size = Rec.Info.Mcast.HwLen = *Buf++;
  2064. Rec.Info.Mcast.ClientId = Buf;
  2065. Buf += Size;
  2066. CopyMemory(&Size, Buf, sizeof(DWORD));
  2067. Buf += sizeof(DWORD);
  2068. if( Size ) {
  2069. Rec.Info.Mcast.Info = (PVOID)Buf;
  2070. Buf += Size;
  2071. }
  2072. CopyMemory(&Rec.Info.Mcast.End, Buf, sizeof(FILETIME));
  2073. Buf += sizeof(FILETIME);
  2074. CopyMemory(&Rec.Info.Mcast.Start, Buf, sizeof(FILETIME));
  2075. Buf += sizeof(FILETIME);
  2076. Rec.Info.Mcast.State = Buf[0];
  2077. Error = AddRec( &Rec );
  2078. break;
  2079. }
  2080. if( NO_ERROR != Error ) return Error;
  2081. }
  2082. return NO_ERROR;
  2083. }
  2084. DWORD __stdcall
  2085. DhcpUpgConvertTempToDhcpDb(
  2086. IN DHCP_ADD_RECORD_ROUTINE AddRec
  2087. )
  2088. {
  2089. DWORD Error;
  2090. if( UpgradeNotNeeded() ) return NO_ERROR;
  2091. if( NULL == AddRec ) {
  2092. //
  2093. // If caller didn't specify, then the intention is to
  2094. // just get us to dump.. so just print the stuff out.
  2095. //
  2096. AddRec = PrintRecord;
  2097. }
  2098. Error = NO_ERROR;
  2099. StartDebug();
  2100. DebugLog( Winnt32LogInformation, MSGERR_STARTLOG2 );
  2101. do {
  2102. Error = ReadRegistry();
  2103. if( NO_ERROR != Error ) break;
  2104. Error = OpenTextFile(TRUE);
  2105. if( NO_ERROR != Error ) {
  2106. if( ERROR_FILE_NOT_FOUND == Error ) {
  2107. Error = NO_ERROR;
  2108. }
  2109. break;
  2110. }
  2111. //
  2112. // Walk through the database-text and parse the fields out
  2113. //
  2114. Error = ProcessDbEntries(
  2115. FileView, LoSize, AddRec
  2116. );
  2117. } while( 0 );
  2118. if( NULL != FileView ) UnmapViewOfFile( FileView );
  2119. FileView = NULL;
  2120. if( NULL != hMapping ) CloseHandle( hMapping );
  2121. hMapping = NULL;
  2122. if( NULL != hTextFile ) CloseHandle( hTextFile );
  2123. hTextFile = NULL;
  2124. if( NO_ERROR != Error ) {
  2125. DebugLog( Winnt32LogError, MSGERR_CONVERT_FAILED, Error );
  2126. } else {
  2127. //
  2128. // Whack the registry keys
  2129. //
  2130. FixRegistryAndDeleteFiles();
  2131. DebugLog( Winnt32LogInformation, MSGERR_CONVERT_SUCCEEDED );
  2132. }
  2133. CloseDebugLog();
  2134. return Error;
  2135. }
  2136. DWORD __stdcall
  2137. DhcpUpgGetLastError(
  2138. VOID
  2139. )
  2140. {
  2141. return LastError;
  2142. }
  2143. DWORD __stdcall
  2144. DhcpUpgCleanupDhcpTempFiles(
  2145. VOID
  2146. )
  2147. {
  2148. DWORD Error;
  2149. //
  2150. // This routine is supposed to delete the special dhcp
  2151. // database file because the operation was cancelled.
  2152. //
  2153. if( UpgradeNotNeeded() ) return NO_ERROR;
  2154. StartDebug();
  2155. Error = ReadRegistry();
  2156. if( NO_ERROR == Error ) {
  2157. DeleteDatabaseTempFile();
  2158. }
  2159. CloseDebugLog();
  2160. return Error;
  2161. }