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.

1124 lines
25 KiB

  1. /*++
  2. Copyright (C) 1999 Microsoft Coporation
  3. Module Name:
  4. main.c
  5. Abstract:
  6. main module
  7. --*/
  8. #include <precomp.h>
  9. #include <dhcpexim.h>
  10. BOOL GlobalIsNT4, GlobalIsNT5;
  11. WCHAR CurrentDir[MAX_PATH*2];
  12. CRITICAL_SECTION DhcpGlobalMemoryCritSect;
  13. CRITICAL_SECTION DhcpGlobalInProgressCritSect;
  14. CHAR DhcpEximOemDatabaseName[2048];
  15. CHAR DhcpEximOemDatabasePath[2048];
  16. HANDLE hLog;
  17. BOOL IsNT4( VOID ) {
  18. return GlobalIsNT4;
  19. }
  20. BOOL IsNT5( VOID ) {
  21. return GlobalIsNT5;
  22. }
  23. #define MAX_PRINTF_LEN 4096
  24. char OutputBuf[MAX_PRINTF_LEN];
  25. VOID
  26. StartDebugLog(
  27. VOID
  28. )
  29. {
  30. CHAR Buffer[MAX_PATH*2];
  31. if( NULL != hLog ) return;
  32. if( 0 == GetWindowsDirectoryA( Buffer, MAX_PATH )) {
  33. ZeroMemory(Buffer, sizeof(Buffer));
  34. }
  35. if( Buffer[strlen(Buffer)-1] != '\\' ) {
  36. strcat(Buffer, "\\");
  37. }
  38. strcat(Buffer, "dhcpexim.log");
  39. hLog = CreateFileA(
  40. Buffer, GENERIC_WRITE,
  41. FILE_SHARE_READ, NULL, OPEN_ALWAYS,
  42. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  43. NULL );
  44. if( hLog == INVALID_HANDLE_VALUE) {
  45. hLog = NULL;
  46. }
  47. if(GetLastError() == ERROR_ALREADY_EXISTS) {
  48. //
  49. // Appending to existing file
  50. //
  51. SetFilePointer(hLog,0,NULL,FILE_END);
  52. }
  53. }
  54. VOID
  55. CloseDebugLog(
  56. VOID
  57. )
  58. {
  59. if( hLog ) {
  60. CloseHandle( hLog );
  61. hLog = NULL;
  62. }
  63. }
  64. DWORD
  65. Tr(
  66. IN LPSTR Format,
  67. ...
  68. )
  69. {
  70. va_list ArgList;
  71. ULONG Length;
  72. strcpy(OutputBuf, "[DHCP] ");
  73. Length = strlen(OutputBuf);
  74. va_start(ArgList, Format);
  75. Length = vsprintf(&OutputBuf[Length], Format, ArgList );
  76. va_end(ArgList);
  77. #if DBG
  78. DbgPrint( (PCH)OutputBuf );
  79. #endif
  80. if( hLog ) {
  81. DWORD Size = strlen(OutputBuf);
  82. WriteFile(
  83. hLog, OutputBuf, Size, &Size, NULL );
  84. }
  85. return NO_ERROR;
  86. }
  87. BOOL
  88. IsPostW2k(
  89. VOID
  90. )
  91. {
  92. HKEY hKey;
  93. DWORD Error, Type, Value, Size;
  94. Error = RegOpenKeyEx(
  95. HKEY_LOCAL_MACHINE,
  96. TEXT("SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Parameters"),
  97. 0, KEY_READ, &hKey );
  98. if( NO_ERROR != Error ) return FALSE;
  99. Type = REG_DWORD; Value = 0; Size = sizeof(Value);
  100. Error = RegQueryValueEx(
  101. hKey, TEXT("Version"), NULL, &Type, (PVOID)&Value, &Size );
  102. RegCloseKey( hKey );
  103. //
  104. // if this value is not present, then upgrade is needed
  105. //
  106. return (Error == NO_ERROR );
  107. }
  108. DWORD
  109. ReconcileLocalService(
  110. IN PULONG Subnets,
  111. IN DWORD nSubnets OPTIONAL
  112. )
  113. /*++
  114. Routine Description:
  115. This routine reconciles the specified scopes.
  116. This is needed after importing as the import doesnt
  117. actually get the bitmask, but only the database entries.
  118. --*/
  119. {
  120. DWORD Error, FinalError, nRead, nTotal, i;
  121. DHCP_RESUME_HANDLE Resume = 0;
  122. LPDHCP_IP_ARRAY IpArray;
  123. if( 0 == nSubnets ) {
  124. IpArray = NULL;
  125. Error = DhcpEnumSubnets(
  126. L"127.0.0.1", &Resume, (ULONG)(-1), &IpArray, &nRead,
  127. &nTotal );
  128. if( NO_ERROR != Error ) {
  129. Tr("DhcpEnumSubnets: %ld\n", Error);
  130. return Error;
  131. }
  132. if( 0 == nRead || 0 == nTotal || IpArray->NumElements == 0 ) {
  133. Tr("DhcpEnumSubnets returned none." );
  134. return NO_ERROR;
  135. }
  136. Error = ReconcileLocalService(
  137. IpArray->Elements, IpArray->NumElements );
  138. DhcpRpcFreeMemory( IpArray );
  139. return Error;
  140. }
  141. //
  142. // Reconcile each of the specified scopes
  143. //
  144. FinalError = NO_ERROR;
  145. for( i = 0; i < nSubnets ; i ++ ) {
  146. LPDHCP_SCAN_LIST ScanList = NULL;
  147. Error = DhcpScanDatabase(
  148. L"127.0.0.1", Subnets[i], TRUE, &ScanList);
  149. if( NULL != ScanList ) DhcpRpcFreeMemory( ScanList );
  150. if( NO_ERROR != Error ) {
  151. Tr("DhcpScanDatabase(0x%lx): %ld\n", Subnets[i], Error);
  152. FinalError = Error;
  153. }
  154. }
  155. return FinalError;
  156. }
  157. DWORD
  158. InitializeAndGetServiceConfig(
  159. OUT PM_SERVER *pServer
  160. )
  161. /*++
  162. Routine Description:
  163. This routine initializes all the modules and obtains the
  164. configuration for the service
  165. --*/
  166. {
  167. DWORD Error;
  168. OSVERSIONINFO Ver;
  169. extern DWORD ClassIdRunningCount; // defined in mm\classdefl.c
  170. //
  171. // Initialize globals
  172. //
  173. GlobalIsNT4 = FALSE;
  174. GlobalIsNT5 = FALSE;
  175. try {
  176. InitializeCriticalSection( &DhcpGlobalMemoryCritSect );
  177. InitializeCriticalSection( &DhcpGlobalInProgressCritSect );
  178. }except ( EXCEPTION_EXECUTE_HANDLER )
  179. {
  180. Error = GetLastError( );
  181. return Error;
  182. }
  183. ClassIdRunningCount = 0x1000;
  184. //
  185. // Other initialization
  186. //
  187. Error = NO_ERROR;
  188. Ver.dwOSVersionInfoSize = sizeof(Ver);
  189. if( FALSE == GetVersionEx(&Ver) ) return GetLastError();
  190. if( Ver.dwMajorVersion == 4 ) GlobalIsNT4 = TRUE;
  191. else if( Ver.dwMajorVersion == 5 ) GlobalIsNT5 = TRUE;
  192. else if( Ver.dwMajorVersion < 4 ) return ERROR_NOT_SUPPORTED;
  193. if( GlobalIsNT5 && IsPostW2k() ) GlobalIsNT5 = FALSE;
  194. #if DBG
  195. DbgPrint("Is NT4: %s, Is NT5: %s\n",
  196. GlobalIsNT4 ? "yes" : "no",
  197. GlobalIsNT5 ? "yes" : "no" );
  198. StartDebugLog();
  199. #endif
  200. //
  201. //
  202. //
  203. SaveBufSize = 0;
  204. SaveBuf = LocalAlloc( LPTR, SAVE_BUF_SIZE );
  205. if( NULL == SaveBuf ) {
  206. return GetLastError();
  207. }
  208. Error = GetCurrentDirectoryW(
  209. sizeof(CurrentDir)/sizeof(WCHAR), CurrentDir );
  210. if( 0 != Error ) {
  211. Error = NO_ERROR;
  212. } else {
  213. Error = GetLastError();
  214. Tr("GetCurrentDirectoryW: %ld\n", Error );
  215. return Error;
  216. }
  217. //
  218. // Set right permissions on the db directory etc..
  219. //
  220. Error = InitializeDatabaseParameters();
  221. if( NO_ERROR != Error ) {
  222. Tr("InitializeDatabaseParameters: %ld\n", Error );
  223. return Error;
  224. }
  225. //
  226. // Now obtain the configuration
  227. //
  228. if( !GlobalIsNT4 && !GlobalIsNT5 ) {
  229. //
  230. // Whistler configuration should be read from the
  231. // database..
  232. //
  233. Error = DhcpeximReadDatabaseConfiguration(pServer);
  234. if( NO_ERROR != Error ) {
  235. Tr("DhcpeximReadDatabaseConfiguration: %ld\n", Error );
  236. }
  237. } else {
  238. //
  239. // NT4 or W2K configuration should be read from registry..
  240. //
  241. Error = DhcpeximReadRegistryConfiguration(pServer);
  242. if( NO_ERROR != Error ) {
  243. Tr("DhcpeximReadRegistryConfiguration: %ld\n", Error );
  244. }
  245. }
  246. return Error;
  247. }
  248. DWORD
  249. CleanupServiceConfig(
  250. IN OUT PM_SERVER Server
  251. )
  252. {
  253. DWORD Error;
  254. if( NULL != SaveBuf ) LocalFree(SaveBuf);
  255. SaveBuf = NULL;
  256. SaveBufSize = 0;
  257. if( NULL != Server ) MemServerFree(Server);
  258. Error = CleanupDatabaseParameters();
  259. if( NO_ERROR != Error ) {
  260. Tr("CleanupServiceConfig: %ld\n", Error );
  261. }
  262. if( FALSE == SetCurrentDirectoryW(CurrentDir) ) {
  263. if( NO_ERROR == Error ) Error = GetLastError();
  264. Tr("SetCurrentDirectoryW: %ld\n", GetLastError());
  265. }
  266. CloseDebugLog();
  267. DeleteCriticalSection( &DhcpGlobalMemoryCritSect );
  268. DeleteCriticalSection( &DhcpGlobalInProgressCritSect );
  269. return Error;
  270. }
  271. DWORD
  272. ExportConfiguration(
  273. IN OUT PM_SERVER SvcConfig,
  274. IN ULONG *Subnets,
  275. IN ULONG nSubnets,
  276. IN HANDLE hFile
  277. )
  278. /*++
  279. Routine Description:
  280. This routine attempts to save the service configuration to a
  281. file after selecting the required subnets.
  282. --*/
  283. {
  284. DWORD Error;
  285. //
  286. // First select the required subnets and get this
  287. // configuration alone.
  288. //
  289. Error = SelectConfiguration( SvcConfig, Subnets, nSubnets );
  290. if( NO_ERROR != Error ) return Error;
  291. //
  292. // Save the configuration to the specified file handle
  293. //
  294. hTextFile = hFile;
  295. Error = SaveConfigurationToFile(SvcConfig);
  296. if( NO_ERROR != Error ) return Error;
  297. //
  298. // Now try to save the database entries to file
  299. //
  300. Error = SaveDatabaseEntriesToFile(Subnets, nSubnets);
  301. if( NO_ERROR != Error ) return Error;
  302. Tr("ExportConfiguration succeeded\n");
  303. return NO_ERROR;
  304. }
  305. DWORD
  306. ImportConfiguration(
  307. IN OUT PM_SERVER SvcConfig,
  308. IN ULONG *Subnets,
  309. IN ULONG nSubnets,
  310. IN LPBYTE Mem, // import file : shared mem
  311. IN ULONG MemSize // shared mem size
  312. )
  313. {
  314. DWORD Error;
  315. PM_SERVER Server;
  316. //
  317. // First obtain the configuration from the file
  318. //
  319. Error = ReadDbEntries( &Mem, &MemSize, &Server );
  320. if( NO_ERROR != Error ) {
  321. Tr("ReadDbEntries: %ld\n", Error );
  322. return Error;
  323. }
  324. //
  325. // Select the configuration required
  326. //
  327. Error = SelectConfiguration( Server, Subnets, nSubnets );
  328. if( NO_ERROR != Error ) return Error;
  329. //
  330. // Merge the configuration along with the svc configuration
  331. //
  332. Error = MergeConfigurations( SvcConfig, Server );
  333. if( NO_ERROR != Error ) {
  334. Tr("MergeConfigurations: %ld\n", Error );
  335. }
  336. MemServerFree( Server );
  337. if( NO_ERROR != Error ) return Error;
  338. //
  339. // Now save the new configuration to registry/disk
  340. //
  341. if( !GlobalIsNT5 && !GlobalIsNT4 ) {
  342. //
  343. // Whistler has config in database
  344. //
  345. Error = DhcpeximWriteDatabaseConfiguration(SvcConfig);
  346. if( NO_ERROR != Error ) {
  347. Tr("DhcpeximWriteDatabaseConfiguration: %ld\n", Error );
  348. }
  349. } else {
  350. Error = DhcpeximWriteRegistryConfiguration(SvcConfig);
  351. if( NO_ERROR != Error ) {
  352. Tr("DhcpeximWriteRegistryConfiguration: %ld\n", Error );
  353. }
  354. }
  355. if( NO_ERROR != Error ) return Error;
  356. //
  357. // Now read the database entries from file and stash them
  358. // into the db.
  359. //
  360. Error = SaveFileEntriesToDatabase(
  361. Mem, MemSize, Subnets, nSubnets );
  362. if( NO_ERROR != Error ) {
  363. Tr("SaveFileEntriesToDatabase: %ld\n", Error );
  364. }
  365. return Error;
  366. }
  367. VOID
  368. IpAddressToStringW(
  369. IN DWORD IpAddress,
  370. IN LPWSTR String // must have enough space preallocated
  371. )
  372. {
  373. PUCHAR pAddress;
  374. ULONG Size;
  375. pAddress = (PUCHAR)&IpAddress;
  376. wsprintf(String, L"%ld.%ld.%ld.%ld",
  377. pAddress[3], pAddress[2], pAddress[1], pAddress[0] );
  378. }
  379. DWORD
  380. StringToIpAddressW(
  381. LPWSTR pwszString
  382. )
  383. {
  384. DWORD dwStrlen = 0;
  385. DWORD dwLen = 0;
  386. DWORD dwRes = 0;
  387. LPSTR pszString = NULL;
  388. if( pwszString == NULL )
  389. return dwRes;
  390. pszString = DhcpUnicodeToOem(pwszString, NULL);
  391. if( pszString )
  392. {
  393. dwRes = DhcpDottedStringToIpAddress(pszString);
  394. }
  395. return dwRes;
  396. }
  397. DWORD
  398. CmdLineDoImport(
  399. IN LPWSTR *Args,
  400. IN ULONG nArgs
  401. )
  402. {
  403. //
  404. // Syntax: Import <filename> <ALL/subnets>
  405. //
  406. LPWSTR FileName;
  407. ULONG Subnets[1024],*pSubnets, nSubnets, MemSize, Error;
  408. HANDLE hFile;
  409. LPBYTE Mem;
  410. PM_SERVER SvcConfig, FileConfig;
  411. if( nArgs == 1 ) return ERROR_BAD_ARGUMENTS;
  412. FileName = Args[0]; Args ++ ; nArgs --;
  413. //
  414. // First open the file
  415. //
  416. Error = OpenTextFile(
  417. FileName, TRUE, &hFile, &Mem, &MemSize );
  418. if( NO_ERROR != Error ) {
  419. Tr("OpenTextFileForRead: %ld\n", Error );
  420. return Error;
  421. }
  422. //
  423. // Now try to parse the rest of the arguments to see if they
  424. // are all ok
  425. //
  426. if( _wcsicmp(Args[0],L"ALL") == 0 ) {
  427. nSubnets = 0; pSubnets = NULL;
  428. } else {
  429. pSubnets = Subnets;
  430. nSubnets = 0;
  431. while( nArgs -- ) {
  432. pSubnets[nSubnets++] = StringToIpAddressW(*Args++);
  433. if( pSubnets[nSubnets-1] == INADDR_ANY ||
  434. pSubnets[nSubnets-1] == INADDR_NONE ) {
  435. Error = ERROR_BAD_ARGUMENTS;
  436. goto Cleanup;
  437. }
  438. }
  439. }
  440. //
  441. // Initialize parameters
  442. //
  443. Error = InitializeAndGetServiceConfig( &SvcConfig );
  444. if( NO_ERROR != Error ) {
  445. Tr("InitializeAndGetServiceConfig: %ld\n", Error );
  446. goto Cleanup;
  447. }
  448. Error = ImportConfiguration(
  449. SvcConfig, pSubnets, nSubnets, Mem, MemSize );
  450. if( NO_ERROR != Error ) {
  451. Tr("ImportConfiguration: %ld\n", Error );
  452. }
  453. //
  454. // Finally cleanup
  455. //
  456. CleanupServiceConfig(SvcConfig);
  457. //
  458. // Also reconcile local server
  459. //
  460. ReconcileLocalService(pSubnets, nSubnets);
  461. Cleanup:
  462. CloseTextFile( hFile, Mem );
  463. return Error;
  464. }
  465. DWORD
  466. CmdLineDoExport(
  467. IN LPWSTR *Args,
  468. IN ULONG nArgs
  469. )
  470. {
  471. //
  472. // Syntax: Import <filename> <ALL/subnets>
  473. //
  474. LPWSTR FileName;
  475. ULONG Subnets[1024],*pSubnets, nSubnets, MemSize, Error;
  476. HANDLE hFile;
  477. LPBYTE Mem;
  478. PM_SERVER SvcConfig, FileConfig;
  479. if( nArgs == 1 ) return ERROR_BAD_ARGUMENTS;
  480. FileName = Args[0]; Args ++ ; nArgs --;
  481. //
  482. // First open the file
  483. //
  484. Error = OpenTextFile(
  485. FileName, FALSE, &hFile, &Mem, &MemSize );
  486. if( NO_ERROR != Error ) {
  487. Tr("OpenTextFileForRead: %ld\n", Error );
  488. return Error;
  489. }
  490. //
  491. // Now try to parse the rest of the arguments to see if they
  492. // are all ok
  493. //
  494. if( _wcsicmp(Args[0],L"ALL") == 0 ) {
  495. nSubnets = 0; pSubnets = NULL;
  496. } else {
  497. pSubnets = Subnets;
  498. nSubnets = 0;
  499. while( nArgs -- ) {
  500. pSubnets[nSubnets++] = StringToIpAddressW(*Args++);
  501. if( pSubnets[nSubnets-1] == INADDR_ANY ||
  502. pSubnets[nSubnets-1] == INADDR_NONE ) {
  503. Error = ERROR_BAD_ARGUMENTS;
  504. goto Cleanup;
  505. }
  506. }
  507. }
  508. //
  509. // Initialize parameters
  510. //
  511. Error = InitializeAndGetServiceConfig( &SvcConfig );
  512. if( NO_ERROR != Error ) {
  513. Tr("InitializeAndGetServiceConfig: %ld\n", Error );
  514. goto Cleanup;
  515. }
  516. //
  517. // Export configuration
  518. //
  519. Error = ExportConfiguration(
  520. SvcConfig, pSubnets, nSubnets, hFile );
  521. if( NO_ERROR != Error ) {
  522. Tr("ExportConfiguration: %ld\n", Error );
  523. }
  524. //
  525. // Finally cleanup
  526. //
  527. CleanupServiceConfig(SvcConfig);
  528. Cleanup:
  529. CloseTextFile( hFile, Mem );
  530. return Error;
  531. }
  532. PM_SERVER
  533. DhcpGetCurrentServer(
  534. VOID
  535. )
  536. {
  537. ASSERT( FALSE );
  538. //
  539. // This is there only to let teh compiler compile without
  540. // having to include dhcpssvc.lib. This routine should never
  541. // be called at all
  542. //
  543. return NULL;
  544. }
  545. BOOL
  546. SubnetMatches(
  547. IN DWORD IpAddress,
  548. IN ULONG *Subnets,
  549. IN ULONG nSubnets
  550. )
  551. {
  552. if( 0 == nSubnets || NULL == Subnets ) return TRUE;
  553. while( nSubnets -- ) {
  554. if( IpAddress == *Subnets ++) return TRUE;
  555. }
  556. return FALSE;
  557. }
  558. VOID
  559. DisableLocalScopes(
  560. IN ULONG *Subnets,
  561. IN ULONG nSubnets
  562. )
  563. {
  564. DWORD Error;
  565. PM_SERVER SvcConfig;
  566. ARRAY_LOCATION Loc;
  567. PM_SUBNET Subnet;
  568. Error = InitializeAndGetServiceConfig(&SvcConfig);
  569. if( NO_ERROR != Error ) {
  570. Tr("DisableLocalScopes: Init: %ld\n", Error );
  571. return;
  572. }
  573. Error = MemArrayInitLoc(&SvcConfig->Subnets, &Loc);
  574. while( NO_ERROR == Error ) {
  575. Error = MemArrayGetElement(
  576. &SvcConfig->Subnets, &Loc, &Subnet);
  577. ASSERT( NO_ERROR == Error && NULL != Subnet );
  578. //
  579. // Disable the subnet
  580. //
  581. if( SubnetMatches(Subnet->Address, Subnets, nSubnets ) ) {
  582. Subnet->State = DISABLED(Subnet->State);
  583. }
  584. Error = MemArrayNextLoc(
  585. &SvcConfig->Subnets, &Loc);
  586. }
  587. //
  588. // Now save the new configuration to registry/disk
  589. //
  590. if( !GlobalIsNT5 && !GlobalIsNT4 ) {
  591. //
  592. // Whistler has config in database
  593. //
  594. Error = DhcpeximWriteDatabaseConfiguration(SvcConfig);
  595. if( NO_ERROR != Error ) {
  596. Tr("DhcpeximWriteDatabaseConfiguration: %ld\n", Error );
  597. }
  598. } else {
  599. Error = DhcpeximWriteRegistryConfiguration(SvcConfig);
  600. if( NO_ERROR != Error ) {
  601. Tr("DhcpeximWriteRegistryConfiguration: %ld\n", Error );
  602. }
  603. }
  604. CleanupServiceConfig(SvcConfig);
  605. }
  606. LPWSTR
  607. MakeName(
  608. IN DWORD IpAddress,
  609. IN LPWSTR Name
  610. )
  611. {
  612. static WCHAR Buffer[40];
  613. PUCHAR pAddress;
  614. LPWSTR RetVal;
  615. ULONG Size;
  616. pAddress = (PUCHAR)&IpAddress;
  617. wsprintf(Buffer, L"[%d.%d.%d.%d] ", pAddress[3], pAddress[2],
  618. pAddress[1], pAddress[0] );
  619. Size = wcslen(Buffer)+1;
  620. if( NULL != Name ) Size += wcslen(Name);
  621. RetVal = LocalAlloc( LPTR, Size * sizeof(WCHAR));
  622. if( NULL == RetVal ) return NULL;
  623. wcscpy(RetVal, Buffer);
  624. if( NULL != Name ) wcscat(RetVal, Name );
  625. return RetVal;
  626. }
  627. DWORD
  628. InitializeCtxt(
  629. IN OUT PDHCPEXIM_CONTEXT Ctxt,
  630. IN PM_SERVER Server
  631. )
  632. {
  633. DWORD Error,i, Size;
  634. ARRAY_LOCATION Loc;
  635. PM_SUBNET Subnet;
  636. //
  637. // First find the # of subnets and allocate array
  638. //
  639. Ctxt->nScopes = i = MemArraySize(&Server->Subnets);
  640. Ctxt->Scopes = LocalAlloc(LPTR, i * sizeof(Ctxt->Scopes[0]) );
  641. if( NULL == Ctxt->Scopes ) {
  642. Ctxt->nScopes = 0;
  643. return GetLastError();
  644. }
  645. //
  646. // Walk through the array and setup each element
  647. //
  648. i = 0;
  649. Error = MemArrayInitLoc( &Server->Subnets, &Loc );
  650. while( NO_ERROR == Error ) {
  651. Error = MemArrayGetElement(&Server->Subnets, &Loc, &Subnet );
  652. ASSERT(NO_ERROR == Error );
  653. Ctxt->Scopes[i].SubnetAddress = Subnet->Address;
  654. Ctxt->Scopes[i].SubnetName = MakeName(Subnet->Address, Subnet->Name);
  655. if( NULL == Ctxt->Scopes[i].SubnetName ) return GetLastError();
  656. i ++;
  657. Error = MemArrayNextLoc(&Server->Subnets, &Loc );
  658. }
  659. return NO_ERROR;
  660. }
  661. DWORD
  662. DhcpEximInitializeContext(
  663. IN OUT PDHCPEXIM_CONTEXT Ctxt,
  664. IN LPWSTR FileName,
  665. IN BOOL fExport
  666. )
  667. {
  668. DWORD Error;
  669. LPVOID Mem;
  670. ZeroMemory(Ctxt, sizeof(*Ctxt));
  671. //
  672. // First set the FileName and fExport fields
  673. //
  674. Ctxt->FileName = FileName;
  675. Ctxt->fExport = fExport;
  676. //
  677. // Next open the file.
  678. //
  679. Error = OpenTextFile(
  680. FileName, !fExport, &Ctxt->hFile, &Ctxt->Mem,
  681. &Ctxt->MemSize );
  682. if( NO_ERROR != Error ) {
  683. Tr("OpenTextFileForRead:%ld\n", Error );
  684. return Error;
  685. }
  686. //
  687. // Initialize parameters and obtain config
  688. //
  689. Error = InitializeAndGetServiceConfig(
  690. (PM_SERVER*)&Ctxt->SvcConfig);
  691. if( NO_ERROR != Error ) {
  692. Tr("InitializeAndGetServiceConfig: %ld\n", Error );
  693. CloseTextFile(Ctxt->hFile, Ctxt->Mem);
  694. return Error;
  695. }
  696. do {
  697. //
  698. // If this is an import, the configuration from the file
  699. // should also be read.
  700. //
  701. if( !fExport ) {
  702. Error = ReadDbEntries(
  703. &Ctxt->Mem, &Ctxt->MemSize,
  704. (PM_SERVER*)&Ctxt->FileConfig );
  705. if( NO_ERROR != Error ) {
  706. Tr("ReadDbEntries: %ld\n", Error );
  707. break;
  708. }
  709. }
  710. //
  711. // Allocate and initialize the Ctxt data structures with the
  712. // service scopes info in case of EXPORT
  713. //
  714. Error = InitializeCtxt(
  715. Ctxt, fExport ? Ctxt->SvcConfig : Ctxt->FileConfig );
  716. if( NO_ERROR != Error ) {
  717. Tr("InitializeCtxt: %ld\n", Error );
  718. break;
  719. }
  720. } while( 0 );
  721. if( NO_ERROR != Error ) {
  722. CleanupServiceConfig( Ctxt->SvcConfig );
  723. if( NULL != Ctxt->FileConfig ) {
  724. MemServerFree( (PM_SERVER)Ctxt->FileConfig );
  725. }
  726. CloseTextFile( Ctxt->hFile, Ctxt->Mem );
  727. }
  728. return Error;
  729. }
  730. DWORD
  731. CalculateSubnets(
  732. IN PDHCPEXIM_CONTEXT Ctxt,
  733. OUT PULONG *Subnets,
  734. OUT ULONG *nSubnets
  735. )
  736. {
  737. DWORD Error, i;
  738. PULONG pSubnets;
  739. //
  740. // First check if there is atleast one unselected subnet
  741. //
  742. (*nSubnets) = 0;
  743. for( i = 0; i < Ctxt->nScopes; i ++ ) {
  744. if( Ctxt->Scopes[i].fSelected ) (*nSubnets) ++;
  745. }
  746. //
  747. // Special case if all subnets are selected
  748. //
  749. if( *nSubnets == Ctxt->nScopes ) {
  750. *nSubnets = 0;
  751. *Subnets = NULL;
  752. return NO_ERROR;
  753. }
  754. //
  755. // Allocate memory
  756. //
  757. *Subnets = LocalAlloc( LPTR, sizeof(DWORD)* (*nSubnets));
  758. if( NULL == *Subnets ) return GetLastError();
  759. //
  760. // Copy the subnets
  761. //
  762. (*nSubnets) = 0;
  763. for( i = 0; i < Ctxt->nScopes; i ++ ) {
  764. if( Ctxt->Scopes[i].fSelected ) {
  765. (*Subnets)[(*nSubnets)++] = Ctxt->Scopes[i].SubnetAddress;
  766. }
  767. }
  768. return NO_ERROR;
  769. }
  770. DWORD
  771. DhcpEximCleanupContext(
  772. IN OUT PDHCPEXIM_CONTEXT Ctxt,
  773. IN BOOL fAbort
  774. )
  775. {
  776. DWORD Error, i;
  777. DWORD *Subnets, nSubnets;
  778. Error = NO_ERROR;
  779. Subnets = NULL;
  780. nSubnets = 0;
  781. //
  782. // If not aborting, attempt to execute the operation
  783. //
  784. if( !fAbort ) do {
  785. Error = CalculateSubnets( Ctxt, &Subnets, &nSubnets );
  786. if( NO_ERROR != Error ) {
  787. Tr("CalculateSubnets: %ld\n", Error );
  788. break;
  789. }
  790. if( Ctxt->fExport ) {
  791. //
  792. // Export the specified subnets out
  793. //
  794. Error = SelectConfiguration(
  795. Ctxt->SvcConfig, Subnets, nSubnets );
  796. if( NO_ERROR != Error ) {
  797. Tr("SelectConfiguration: %ld\n", Error );
  798. break;
  799. }
  800. Error = SaveConfigurationToFile( Ctxt->SvcConfig);
  801. if( NO_ERROR != Error ) {
  802. Tr("SaveConfigurationToFile: %ld\n", Error );
  803. break;
  804. }
  805. //
  806. // Now try to save the database entries to file
  807. //
  808. Error = SaveDatabaseEntriesToFile(Subnets, nSubnets);
  809. if( NO_ERROR != Error ) {
  810. Tr("SaveDatabaseEntriesToFile: %ld\n", Error );
  811. }
  812. break;
  813. }
  814. //
  815. // Import the specified subnets in
  816. //
  817. Error = SelectConfiguration(
  818. Ctxt->FileConfig, Subnets, nSubnets );
  819. if( NO_ERROR != Error ) {
  820. Tr("SelectConfiguration: %ld\n", Error );
  821. break;
  822. }
  823. Error = MergeConfigurations(
  824. Ctxt->SvcConfig, Ctxt->FileConfig );
  825. if( NO_ERROR != Error ) {
  826. Tr("MergeConfigurations: %ld\n", Error );
  827. break;
  828. }
  829. //
  830. // Now save the new configuration to registry/disk
  831. //
  832. if( !GlobalIsNT5 && !GlobalIsNT4 ) {
  833. //
  834. // Whistler has config in database
  835. //
  836. Error = DhcpeximWriteDatabaseConfiguration(Ctxt->SvcConfig);
  837. if( NO_ERROR != Error ) {
  838. Tr("DhcpeximWriteDatabaseConfiguration: %ld\n", Error );
  839. }
  840. } else {
  841. Error = DhcpeximWriteRegistryConfiguration(Ctxt->SvcConfig);
  842. if( NO_ERROR != Error ) {
  843. Tr("DhcpeximWriteRegistryConfiguration: %ld\n", Error );
  844. }
  845. }
  846. if( NO_ERROR != Error ) break;
  847. //
  848. // Now read the database entries from file and stash them
  849. // into the db.
  850. //
  851. Error = SaveFileEntriesToDatabase(
  852. Ctxt->Mem, Ctxt->MemSize, Subnets, nSubnets );
  853. if( NO_ERROR != Error ) {
  854. Tr("SaveFileEntriesToDatabase: %ld\n", Error );
  855. }
  856. } while( 0 );
  857. //
  858. // Cleanup
  859. //
  860. if( NULL != Ctxt->SvcConfig ) {
  861. CleanupServiceConfig( Ctxt->SvcConfig );
  862. }
  863. if( NULL != Ctxt->FileConfig ) {
  864. MemServerFree( (PM_SERVER)Ctxt->FileConfig );
  865. }
  866. if( !fAbort && Ctxt->fExport == FALSE ) {
  867. //
  868. // Also reconcile local server
  869. //
  870. ReconcileLocalService( Subnets, nSubnets );
  871. }
  872. CloseTextFile( Ctxt->hFile, Ctxt->Mem );
  873. //
  874. // Walk through the array and free up pointers
  875. //
  876. for( i = 0 ; i < Ctxt->nScopes ; i ++ ) {
  877. if( Ctxt->Scopes[i].SubnetName ) {
  878. LocalFree( Ctxt->Scopes[i].SubnetName );
  879. }
  880. }
  881. if( Ctxt->Scopes ) LocalFree( Ctxt->Scopes );
  882. Ctxt->Scopes = NULL; Ctxt->nScopes = 0;
  883. if( !fAbort && Ctxt->fExport && Ctxt->fDisableExportedScopes ) {
  884. //
  885. // Fix the local scopes to all be disabled
  886. //
  887. DisableLocalScopes(Subnets, nSubnets);
  888. }
  889. if( NULL != Subnets && 0 != nSubnets ) {
  890. LocalFree( Subnets );
  891. }
  892. return Error;
  893. }