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.

1419 lines
39 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dmsync.c
  5. Abstract:
  6. Contains the registry synchronization code for the Cluster Database
  7. Manager.
  8. Author:
  9. John Vert (jvert) 5/23/1996
  10. Revision History:
  11. --*/
  12. #include "dmp.h"
  13. #if NO_SHARED_LOCKS
  14. extern CRITICAL_SECTION gLockDmpRoot;
  15. #else
  16. extern RTL_RESOURCE gLockDmpRoot;
  17. #endif
  18. const WCHAR DmpClusterParametersKeyName[] = L"Cluster";
  19. extern const UNICODE_STRING RegistryMachineClusterString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Cluster");
  20. extern const OBJECT_ATTRIBUTES RegistryMachineClusterObja = RTL_CONSTANT_OBJECT_ATTRIBUTES(&RegistryMachineClusterString, OBJ_CASE_INSENSITIVE);
  21. //
  22. // Private Constants
  23. //
  24. #define CHUNK_SIZE 4096
  25. //
  26. // Private macro
  27. //
  28. #define ClosePipe( _pipe ) \
  29. (_pipe.push)(_pipe.state, \
  30. NULL, \
  31. 0 ) \
  32. //
  33. // Client-Side Utility Routines
  34. //
  35. void
  36. FilePipePush(
  37. FILE_PIPE_STATE *state,
  38. unsigned char *pBuffer,
  39. unsigned long BufferSize
  40. )
  41. {
  42. DWORD dwBytesWritten;
  43. DWORD dwStatus;
  44. dwStatus = NmCryptor_Decrypt(&state->Cryptor, pBuffer, BufferSize);
  45. if (dwStatus != ERROR_SUCCESS) {
  46. ClRtlLogPrint(LOG_CRITICAL,
  47. "FilePipePush :: Decryption failed with error %1!u!\n",
  48. dwStatus);
  49. RpcRaiseException(dwStatus);
  50. }
  51. if (BufferSize != 0) {
  52. if (!QfsWriteFile (state->hFile,
  53. state->Cryptor.PayloadBuffer,
  54. state->Cryptor.PayloadSize,
  55. &dwBytesWritten,
  56. NULL))
  57. {
  58. dwStatus = GetLastError();
  59. ClRtlLogPrint(LOG_CRITICAL,
  60. "FilePipePush :: Write file failed with error %1!u!\n",
  61. dwStatus);
  62. RpcRaiseException(dwStatus);
  63. }
  64. }
  65. }
  66. void
  67. FilePipePull(
  68. FILE_PIPE_STATE *state,
  69. unsigned char *pBuffer,
  70. unsigned long BufferSize,
  71. unsigned long __RPC_FAR *Written
  72. )
  73. {
  74. DWORD dwBytesRead;
  75. BOOL Success;
  76. DWORD dwStatus;
  77. if (BufferSize != 0) {
  78. NmCryptor_PrepareEncryptionBuffer(
  79. &state->Cryptor, pBuffer, BufferSize);
  80. Success = QfsReadFile (state->hFile,
  81. state->Cryptor.PayloadBuffer,
  82. state->Cryptor.PayloadSize,
  83. &dwBytesRead,
  84. NULL);
  85. if (!Success)
  86. {
  87. dwStatus = GetLastError();
  88. ClRtlLogPrint(LOG_CRITICAL,
  89. "FilePipePush :: Read file failed with error %1!u!\n",
  90. dwStatus);
  91. RpcRaiseException(dwStatus);
  92. }
  93. dwStatus = NmCryptor_Encrypt(&state->Cryptor, dwBytesRead);
  94. if (dwStatus != ERROR_SUCCESS)
  95. {
  96. ClRtlLogPrint(LOG_CRITICAL,
  97. "FilePipePush :: Encryption failed with error %1!u!\n",
  98. dwStatus);
  99. RpcRaiseException(dwStatus);
  100. }
  101. *Written = state->Cryptor.EncryptedSize;
  102. }
  103. }
  104. void
  105. PipeAlloc (
  106. FILE_PIPE_STATE *state,
  107. unsigned long RequestedSize,
  108. unsigned char **buf,
  109. unsigned long *ActualSize
  110. )
  111. {
  112. *buf = state->pBuffer;
  113. *ActualSize = (RequestedSize < state->BufferSize ?
  114. RequestedSize :
  115. state->BufferSize);
  116. }
  117. VOID
  118. DmInitFilePipe(
  119. IN PFILE_PIPE FilePipe,
  120. IN QfsHANDLE hFile
  121. )
  122. /*++
  123. Routine Description:
  124. Initializes a file pipe.
  125. Arguments:
  126. FilePipe - Supplies a pointer to the file pipe to be initialized
  127. hFile - Supplies a handle to the file to be transmitted.
  128. Return Value:
  129. None.
  130. --*/
  131. {
  132. FilePipe->State.hFile = hFile;
  133. FilePipe->State.BufferSize = CHUNK_SIZE;
  134. FilePipe->State.pBuffer = LocalAlloc(LMEM_FIXED, CHUNK_SIZE);
  135. if (FilePipe->State.pBuffer == NULL) {
  136. CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
  137. }
  138. FilePipe->Pipe.state = (char __RPC_FAR *)&FilePipe->State;
  139. FilePipe->Pipe.alloc = (void __RPC_FAR *)PipeAlloc;
  140. FilePipe->Pipe.push = (void __RPC_FAR *)FilePipePush;
  141. FilePipe->Pipe.pull = (void __RPC_FAR *)FilePipePull;
  142. NmCryptor_Init(&FilePipe->State.Cryptor, TRUE);
  143. }
  144. VOID
  145. DmFreeFilePipe(
  146. IN PFILE_PIPE FilePipe
  147. )
  148. /*++
  149. Routine Description:
  150. Frees a file pipe initialized by DmInitFilePipe
  151. Arguments:
  152. FilePipe - Supplies the file pipe to be freed.
  153. Return Value:
  154. None
  155. --*/
  156. {
  157. NmCryptor_Destroy(&FilePipe->State.Cryptor);
  158. LocalFree(FilePipe->State.pBuffer);
  159. }
  160. DWORD
  161. DmPullFile(
  162. IN LPCWSTR FileName,
  163. IN BYTE_PIPE Pipe
  164. )
  165. /*++
  166. Routine Description:
  167. Creates a new file and pulls the data down the RPC pipe
  168. Arguments:
  169. FileName - Supplies the name of the file.
  170. Pipe - Supplies the RPC pipe to pull the data from.
  171. Return Value:
  172. ERROR_SUCCESS if successful
  173. Win32 error code otherwise
  174. --*/
  175. {
  176. QfsHANDLE File;
  177. DWORD Status = ERROR_SUCCESS;
  178. PUCHAR Buffer;
  179. DWORD BytesRead;
  180. NM_CRYPTOR Decryptor;
  181. NmCryptor_Init(&Decryptor, TRUE);
  182. //
  183. // Create a new file to hold the bits from the client.
  184. //
  185. File = QfsCreateFile(FileName,
  186. GENERIC_READ | GENERIC_WRITE,
  187. 0,
  188. NULL,
  189. CREATE_ALWAYS,
  190. 0,
  191. NULL);
  192. if (!QfsIsHandleValid(File)) {
  193. Status = GetLastError();
  194. ClRtlLogPrint(LOG_UNUSUAL,
  195. "[DM] DmPullFile failed to create file %1!ws! error %2!d!\n",
  196. FileName,
  197. Status);
  198. return(Status);
  199. }
  200. Buffer = LocalAlloc(LMEM_FIXED, CHUNK_SIZE);
  201. if (Buffer == NULL) {
  202. Status = ERROR_NOT_ENOUGH_MEMORY;
  203. QfsCloseHandle(File);
  204. CL_UNEXPECTED_ERROR( Status );
  205. return (Status);
  206. }
  207. try {
  208. do {
  209. (Pipe.pull)(Pipe.state,
  210. Buffer,
  211. CHUNK_SIZE,
  212. &BytesRead);
  213. if (BytesRead == 0) {
  214. break;
  215. }
  216. Status = NmCryptor_Decrypt(&Decryptor, Buffer, BytesRead);
  217. if (Status != ERROR_SUCCESS)
  218. {
  219. ClRtlLogPrint(LOG_UNUSUAL,
  220. "[DM] DmPullFile :: Failed to decrypt buffer for '%1!ws!' error %2!d!\n",
  221. FileName, Status);
  222. break;
  223. }
  224. if (!QfsWriteFile(File,
  225. Decryptor.PayloadBuffer,
  226. Decryptor.PayloadSize,
  227. &BytesRead,
  228. NULL))
  229. {
  230. Status = GetLastError();
  231. ClRtlLogPrint(LOG_UNUSUAL,
  232. "[DM] DmPullFile :: WriteFile to file failed with error %1!ws! error %2!d!\n",
  233. FileName, Status);
  234. break;
  235. }
  236. } while ( TRUE );
  237. } except (I_RpcExceptionFilter(RpcExceptionCode())) {
  238. Status = GetExceptionCode();
  239. ClRtlLogPrint(LOG_ERROR,
  240. "[DM] DmPullFile :: Exception code 0x%1!08lx! raised for file %2!ws!\n",
  241. Status, FileName);
  242. }
  243. LocalFree(Buffer);
  244. QfsFlushFileBuffers(File);
  245. QfsCloseHandle(File);
  246. NmCryptor_Destroy(&Decryptor);
  247. return(Status);
  248. }
  249. DWORD
  250. DmPushFile(
  251. IN LPCWSTR FileName,
  252. IN BYTE_PIPE Pipe,
  253. IN BOOL EncryptData
  254. )
  255. /*++
  256. Routine Description:
  257. Opens a file and pushes it down the RPC pipe
  258. Arguments:
  259. FileName - Supplies the name of the file.
  260. Pipe - Supplies the RPC pipe to push it down.
  261. EncryptData - If TRUE, data passed over the Rpc pipe will be encrypted
  262. (If NT5 node is in the cluster, data won't be encrypted)
  263. Return Value:
  264. ERROR_SUCCESS if successful
  265. Win32 error code otherwise
  266. --*/
  267. {
  268. QfsHANDLE File;
  269. DWORD Status = ERROR_SUCCESS;
  270. PUCHAR Buffer;
  271. DWORD BytesRead;
  272. NM_CRYPTOR Encryptor;
  273. NmCryptor_Init(&Encryptor, EncryptData);
  274. //
  275. // Got a file with the right bits in it. Push it down
  276. // to the client.
  277. //
  278. File = QfsCreateFile(FileName,
  279. GENERIC_READ,
  280. FILE_SHARE_READ,
  281. NULL,
  282. OPEN_EXISTING,
  283. 0,
  284. NULL);
  285. if (!QfsIsHandleValid(File)) {
  286. Status = GetLastError();
  287. ClosePipe( Pipe );
  288. ClRtlLogPrint(LOG_UNUSUAL,
  289. "[DM] DmPushFile failed to open file %1!ws! error %2!d!\n",
  290. FileName,
  291. Status);
  292. return(Status);
  293. }
  294. Buffer = LocalAlloc(LMEM_FIXED, CHUNK_SIZE);
  295. if (Buffer == NULL) {
  296. ClosePipe( Pipe );
  297. Status = ERROR_NOT_ENOUGH_MEMORY;
  298. QfsCloseHandle(File);
  299. CL_UNEXPECTED_ERROR( Status );
  300. return(Status);
  301. }
  302. try {
  303. do {
  304. NmCryptor_PrepareEncryptionBuffer(
  305. &Encryptor, Buffer, CHUNK_SIZE);
  306. if (!QfsReadFile(File,
  307. Encryptor.PayloadBuffer,
  308. Encryptor.PayloadSize,
  309. &BytesRead,
  310. NULL))
  311. {
  312. Status = GetLastError();
  313. ClRtlLogPrint(LOG_CRITICAL,
  314. "[DM] DmPushFile failed to read file %1!ws! error %2!d!\n",
  315. FileName, Status);
  316. break;
  317. }
  318. Status = NmCryptor_Encrypt(&Encryptor, BytesRead);
  319. if (Status != ERROR_SUCCESS) {
  320. ClRtlLogPrint(LOG_CRITICAL,
  321. "[DM] DmPushFile failed to encrypt file %1!ws! error %2!d!\n",
  322. FileName, Status);
  323. break;
  324. }
  325. (Pipe.push)(Pipe.state,
  326. Buffer,
  327. Encryptor.EncryptedSize);
  328. } while ( BytesRead != 0 );
  329. } except (I_RpcExceptionFilter(RpcExceptionCode())) {
  330. Status = GetExceptionCode();
  331. ClRtlLogPrint(LOG_ERROR,
  332. "[DM] DmPushFile :: Exception code 0x%1!08lx! raised for file %2!ws!\n",
  333. Status, FileName);
  334. }
  335. LocalFree(Buffer);
  336. QfsCloseHandle(File);
  337. NmCryptor_Destroy(&Encryptor);
  338. return(Status);
  339. }
  340. DWORD
  341. DmpSyncDatabase(
  342. IN RPC_BINDING_HANDLE RpcBinding,
  343. IN OPTIONAL LPCWSTR Directory
  344. )
  345. /*++
  346. Routine Description:
  347. Connects to a remote node and attempts to sync with its
  348. cluster database.
  349. Arguments:
  350. RpcBinding - The RPC binding handle to use to sync the database.
  351. Directory - if present, supplies the directory where CLUSDB should
  352. be created.
  353. Return Value:
  354. ERROR_SUCCESS if the database was successfully updated.
  355. Win32 error otherwise
  356. --*/
  357. {
  358. DWORD Status;
  359. WCHAR FileName[MAX_PATH+1];
  360. FILE_PIPE FilePipe;
  361. QfsHANDLE hFile;
  362. //
  363. // Issue conditional synchronization
  364. //
  365. Status = DmCreateTempFileName(FileName);
  366. if (Status == ERROR_SUCCESS) {
  367. hFile = QfsCreateFile(FileName,
  368. GENERIC_READ | GENERIC_WRITE,
  369. 0,
  370. NULL,
  371. CREATE_ALWAYS,
  372. 0,
  373. NULL);
  374. if (!QfsIsHandleValid(hFile)) {
  375. Status = GetLastError();
  376. CL_UNEXPECTED_ERROR( Status );
  377. } else {
  378. DmInitFilePipe(&FilePipe, hFile);
  379. Status = DmSyncDatabase(RpcBinding,
  380. FilePipe.Pipe);
  381. DmFreeFilePipe(&FilePipe);
  382. //
  383. // Flush the file buffers to avoid corrupting CLUSDB on a power failure.
  384. //
  385. QfsFlushFileBuffers(hFile);
  386. QfsCloseHandle(hFile);
  387. if (Status == ERROR_SUCCESS) {
  388. //
  389. // A new registry file was successfully downloaded.
  390. // Install it into the current registry.
  391. //
  392. ClRtlLogPrint(LOG_UNUSUAL,"[DM] Obtained new database.\n");
  393. //acquire the exclusive locks so that no new keys are opened while
  394. // the registry is being reinstated
  395. ACQUIRE_EXCLUSIVE_LOCK(gLockDmpRoot);
  396. // hold the key lock as well
  397. EnterCriticalSection(&KeyLock);
  398. // Invalidate any open keys
  399. DmpInvalidateKeys();
  400. Status = DmInstallDatabase(FileName, Directory, TRUE);
  401. if (Status != ERROR_SUCCESS) {
  402. ClRtlLogPrint(LOG_CRITICAL,
  403. "[DM] DmpSyncDatabase failed, error %1!u!.\n",
  404. Status);
  405. }
  406. // Reopen the keys for read/write access
  407. DmpReopenKeys();
  408. // release the locks
  409. LeaveCriticalSection(&KeyLock);
  410. RELEASE_LOCK(gLockDmpRoot);
  411. } else {
  412. ClRtlLogPrint(LOG_UNUSUAL,
  413. "[DM] Failed to get a new database, status %1!u!\n",
  414. Status
  415. );
  416. CL_UNEXPECTED_ERROR(Status);
  417. }
  418. QfsDeleteFile(FileName);
  419. }
  420. }
  421. return(Status);
  422. }
  423. DWORD
  424. DmInstallDatabase(
  425. IN LPWSTR FileName,
  426. IN OPTIONAL LPCWSTR Directory,
  427. IN BOOL bDeleteSrcFile
  428. )
  429. /*++
  430. Routine Description:
  431. Installs a new cluster registry database from the specified file
  432. Arguments:
  433. FileName - The name of the file from which to read the registry database
  434. to install.
  435. Directory - if present, supplies the directory where the CLUSDB file should
  436. be created.
  437. if not present, the current directory is used.
  438. bDeleteSrcFile - Delete the Source file represented by FileName.
  439. Return Value:
  440. ERROR_SUCCESS if the installation completed successfully
  441. Win32 error code otherwise.
  442. --*/
  443. {
  444. DWORD Status;
  445. BOOLEAN WasEnabled;
  446. WCHAR Path[MAX_PATH];
  447. WCHAR *p;
  448. WCHAR BkpPath[MAX_PATH];
  449. Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  450. &WasEnabled);
  451. if (Status != ERROR_SUCCESS) {
  452. if (Status == STATUS_PRIVILEGE_NOT_HELD) {
  453. ClRtlLogPrint(LOG_CRITICAL,
  454. "[DM] Restore privilege not held by cluster service\n");
  455. } else {
  456. ClRtlLogPrint(LOG_CRITICAL,
  457. "[DM] Attempt to enable restore privilege failed %1!lx!\n",Status);
  458. }
  459. return(Status);
  460. }
  461. //
  462. // Restart the registry watcher thread so it is not trying to use
  463. // DmpRoot while we are messing with things.
  464. //
  465. ACQUIRE_EXCLUSIVE_LOCK(gLockDmpRoot);
  466. DmpRestartFlusher();
  467. //
  468. // Close DmpRoot (it should be the only thing open) so that we can
  469. // unload the current cluster database.
  470. //
  471. RegCloseKey(DmpRoot);
  472. RegCloseKey(DmpRootCopy);
  473. DmpRoot = DmpRootCopy = NULL;
  474. Status = RegUnLoadKey(HKEY_LOCAL_MACHINE, DmpClusterParametersKeyName);
  475. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  476. WasEnabled);
  477. if (Status == ERROR_SUCCESS) {
  478. //
  479. // Get the CLUSDB full pathname.
  480. //
  481. if (Directory == NULL) {
  482. Status = GetModuleFileName(NULL, Path, MAX_PATH);
  483. //
  484. // GetModuleFileName may not NULL terminate the Path.
  485. //
  486. Path [ RTL_NUMBER_OF ( Path ) - 1 ] = UNICODE_NULL;
  487. if (Status == 0) {
  488. ClRtlLogPrint(LOG_CRITICAL,
  489. "[DM] Couldn't find cluster database\n");
  490. Status = GetLastError();
  491. } else {
  492. Status = ERROR_SUCCESS;
  493. p=wcsrchr(Path, L'\\');
  494. if (p != NULL) {
  495. *p = L'\0';
  496. wcscpy(BkpPath, Path);
  497. #ifdef OLD_WAY
  498. wcscat(Path, L"\\CLUSDB");
  499. #else // OLD_WAY
  500. wcscat(Path, L"\\"CLUSTER_DATABASE_NAME );
  501. #endif // OLD_WAY
  502. wcscat(BkpPath, L"\\"CLUSTER_DATABASE_TMPBKP_NAME);
  503. } else {
  504. CL_UNEXPECTED_ERROR(ERROR_FILE_NOT_FOUND);
  505. }
  506. }
  507. } else {
  508. lstrcpyW(Path, Directory);
  509. lstrcpyW(BkpPath, Path);
  510. #ifdef OLD_WAY
  511. wcscat(Path, L"\\CLUSDB");
  512. #else // OLD_WAY
  513. wcscat(Path, L"\\"CLUSTER_DATABASE_NAME );
  514. #endif // OLD_WAY
  515. wcscat(BkpPath, L"\\"CLUSTER_DATABASE_TMPBKP_NAME);
  516. }
  517. if (Status == ERROR_SUCCESS) {
  518. //
  519. // Now copy the supplied file to CLUSDB
  520. //
  521. Status = DmpSafeDatabaseCopy(FileName, Path, BkpPath, bDeleteSrcFile);
  522. if (Status != ERROR_SUCCESS) {
  523. ClRtlLogPrint(LOG_CRITICAL,
  524. "[DM] DmInstallDatabase :: DmpSafeDatabaseCopy() failed %1!d!\n",
  525. Status);
  526. // SS: BUG BUG - we should not reload the old hive
  527. //on a join, that would be catastrophic to continue
  528. //on a form, while uploading from a checkpoint file
  529. // it would be the same
  530. //
  531. // Try and reload the old hive
  532. //
  533. // Status = DmpLoadHive(Path);
  534. CL_UNEXPECTED_ERROR(Status);
  535. } else {
  536. //
  537. // Finally, reload the hive.
  538. //
  539. Status = DmpLoadHive(Path);
  540. }
  541. }
  542. } else {
  543. ClRtlLogPrint(LOG_CRITICAL,
  544. "[DM] RegUnloadKey of existing database failed %1!d!\n",
  545. Status);
  546. goto FnExit;
  547. }
  548. if (Status != ERROR_SUCCESS)
  549. {
  550. ClRtlLogPrint(LOG_CRITICAL,
  551. "[DM] DmInstallDatabase :: failed to load hive %1!d!\n",
  552. Status);
  553. goto FnExit;
  554. }
  555. //
  556. // Reopen DmpRoot and DmpRootCopy
  557. //
  558. Status = RegOpenKeyW(HKEY_LOCAL_MACHINE,
  559. DmpClusterParametersKeyName,
  560. &DmpRoot);
  561. if ( Status != ERROR_SUCCESS ) {
  562. CL_UNEXPECTED_ERROR(Status);
  563. goto FnExit;
  564. }
  565. Status = RegOpenKeyW(HKEY_LOCAL_MACHINE,
  566. DmpClusterParametersKeyName,
  567. &DmpRootCopy);
  568. if ( Status != ERROR_SUCCESS ) {
  569. CL_UNEXPECTED_ERROR(Status);
  570. goto FnExit;
  571. }
  572. //
  573. // HACKHACK John Vert (jvert) 6/3/1997
  574. // There is a bug in the registry with refresh
  575. // where the Parent field in the root cell doesn't
  576. // get flushed to disk, so it gets blasted if we
  577. // do a refresh. Then we crash in unload. So flush
  578. // out the registry to disk here to make sure the
  579. // right Parent field gets written to disk.
  580. //
  581. if (Status == ERROR_SUCCESS) {
  582. DWORD Dummy=0;
  583. //
  584. // Make something dirty in the root
  585. //
  586. RegSetValueEx(DmpRoot,
  587. L"Valid",
  588. 0,
  589. REG_DWORD,
  590. (PBYTE)&Dummy,
  591. sizeof(Dummy));
  592. RegDeleteValue(DmpRoot, L"Valid");
  593. Status = RegFlushKey(DmpRoot);
  594. if (Status != ERROR_SUCCESS)
  595. {
  596. CL_UNEXPECTED_ERROR(Status);
  597. ClRtlLogPrint(LOG_CRITICAL,
  598. "[DM] DmInstallDatabase : RegFlushKey failed with error %1!d!\n",
  599. Status);
  600. }
  601. }
  602. FnExit:
  603. RELEASE_LOCK(gLockDmpRoot);
  604. return(Status);
  605. }
  606. DWORD
  607. DmGetDatabase(
  608. IN HKEY hKey,
  609. IN LPWSTR FileName
  610. )
  611. /*++
  612. Routine Description:
  613. Writes the registry database to a specified file.
  614. Arguments:
  615. hKey - Supplies the root of the registry tree to get.
  616. FileName - The name of the file into which to write the current
  617. registry database.
  618. Return Value:
  619. ERROR_SUCCESS if the update completed successfully
  620. Win32 error code otherwise.
  621. --*/
  622. {
  623. BOOLEAN WasEnabled;
  624. DWORD Status;
  625. NTSTATUS Error;
  626. //
  627. // Make sure this file does not exist already.
  628. //
  629. QfsDeleteFile(FileName);
  630. Status = ClRtlEnableThreadPrivilege(SE_BACKUP_PRIVILEGE,
  631. &WasEnabled);
  632. if ( Status != STATUS_SUCCESS ) {
  633. CL_LOGFAILURE( Status );
  634. goto FnExit;
  635. }
  636. Status = QfsRegSaveKey(hKey,
  637. FileName,
  638. NULL);
  639. // this is used for checkpointing and shouldnt fail, but if it does we
  640. // will log an event and delete the file
  641. if ( Status != ERROR_SUCCESS ) {
  642. CL_LOGFAILURE( Status );
  643. CsLogEventData1( LOG_CRITICAL,
  644. CS_DISKWRITE_FAILURE,
  645. sizeof(Status),
  646. &Status,
  647. FileName );
  648. QfsDeleteFile(FileName);
  649. }
  650. Error = ClRtlRestoreThreadPrivilege(SE_BACKUP_PRIVILEGE,
  651. WasEnabled);
  652. if (Error != ERROR_SUCCESS)
  653. {
  654. CL_UNEXPECTED_ERROR(Error);
  655. }
  656. FnExit:
  657. return(Status);
  658. }
  659. //
  660. //
  661. // Server-side join routines.
  662. //
  663. //
  664. error_status_t
  665. s_DmSyncDatabase(
  666. IN handle_t IDL_handle,
  667. OUT BYTE_PIPE Regdata
  668. )
  669. /*++
  670. Routine Description:
  671. Pushes a new configuration database to a joining node.
  672. Arguments:
  673. IDL_handle - RPC binding handle, not used.
  674. Regdata - The RPC data pipe to use to transfer the data.
  675. Return Value:
  676. ERROR_SUCCESS if the update completed successfully
  677. Win32 error code otherwise.
  678. --*/
  679. {
  680. HANDLE File;
  681. DWORD Status;
  682. WCHAR FileName[MAX_PATH+1];
  683. ClRtlLogPrint(LOG_UNUSUAL, "[DM] Supplying database to joining node.\n");
  684. Status = DmCreateTempFileName(FileName);
  685. if (Status == ERROR_SUCCESS) {
  686. DmCommitRegistry(); // Ensure up-to-date snapshot
  687. //
  688. // Chittur Subbaraman (chitturs) - 01/19/2001
  689. //
  690. // Hold the root lock before trying to save the hive. This is necessary so that
  691. // an NtRestoreKey/RegCloseKey on the root key is not in progress at the time
  692. // the save is attempted.
  693. //
  694. ACQUIRE_EXCLUSIVE_LOCK( gLockDmpRoot );
  695. Status = DmGetDatabase(DmpRoot,FileName);
  696. RELEASE_LOCK ( gLockDmpRoot );
  697. if (Status != ERROR_SUCCESS) {
  698. ClosePipe(Regdata);
  699. CL_UNEXPECTED_ERROR( Status );
  700. } else {
  701. Status = DmPushFile(FileName, Regdata, FALSE); // FALSE == don't encrypt
  702. QfsDeleteFile(FileName);
  703. }
  704. } else {
  705. RpcRaiseException( Status );
  706. ClosePipe(Regdata);
  707. CL_UNEXPECTED_ERROR( Status );
  708. }
  709. ClRtlLogPrint(LOG_UNUSUAL,
  710. "[DM] Finished supplying database to joining node.\n"
  711. );
  712. return(Status);
  713. }
  714. DWORD
  715. DmCreateTempFileName(
  716. OUT LPWSTR FileName
  717. )
  718. /*++
  719. Routine Description:
  720. Creates a temporary filename for use by the cluster service.
  721. Arguments:
  722. FileName - Returns the name of the temporary file. The buffer
  723. pointed to must be big enough for at least MAX_PATH
  724. characters.
  725. Return Value:
  726. ERROR_SUCCESS if successful.
  727. Win32 error code otherwise
  728. --*/
  729. {
  730. WCHAR TempPath[MAX_PATH];
  731. DWORD Status;
  732. GetTempPath(sizeof(TempPath)/sizeof(WCHAR),TempPath);
  733. Status = QfsGetTempFileName(TempPath,L"CLS",0,FileName);
  734. if (Status == 0) {
  735. //
  736. // Somebody has probably set the TMP variable incorrectly.
  737. // Just use the current directory.
  738. //
  739. Status = QfsGetTempFileName(L".", L"CLS",0,FileName);
  740. if (Status == 0) {
  741. Status = GetLastError();
  742. CL_UNEXPECTED_ERROR( Status );
  743. return(Status);
  744. }
  745. }
  746. //
  747. // Set DACL on the file handle object granting full rights only to admin and owner.
  748. //
  749. Status = QfsSetFileSecurityInfo( FileName,
  750. GENERIC_ALL, // for Admins
  751. GENERIC_ALL, // for Owner
  752. 0 ); // for Everyone
  753. if ( Status != ERROR_SUCCESS )
  754. {
  755. ClRtlLogPrint(LOG_CRITICAL,
  756. "[DM] DmCreateTempFile: ClRtlSetObjSecurityInfo failed for file %1!ws!, Status=%2!u!\r\n",
  757. FileName,
  758. Status);
  759. return ( Status );
  760. }
  761. return( ERROR_SUCCESS );
  762. }
  763. DWORD
  764. DmpLoadHive(
  765. IN LPCWSTR Path
  766. )
  767. /*++
  768. Routine Description:
  769. Loads the cluster database into HKLM\Cluster
  770. Arguments:
  771. Path - Supplies the fully qualified filename of the cluster database.
  772. Return Value:
  773. ERROR_SUCCESS if successful
  774. Win32 error code otherwise
  775. --*/
  776. {
  777. BOOLEAN WasEnabled;
  778. RTL_RELATIVE_NAME_U RelativeName;
  779. OBJECT_ATTRIBUTES SourceFile;
  780. UNICODE_STRING FileName;
  781. NTSTATUS Status;
  782. BOOLEAN ErrorFlag;
  783. LPWSTR FreeBuffer;
  784. //
  785. // If the cluster database is not loaded, load it now.
  786. //
  787. ClRtlLogPrint(LOG_NOISE,
  788. "[DM] Loading cluster database from %1!ws!\n", Path);
  789. ErrorFlag = RtlDosPathNameToRelativeNtPathName_U(Path,
  790. &FileName,
  791. NULL,
  792. &RelativeName);
  793. if (!ErrorFlag) {
  794. ClRtlLogPrint(LOG_CRITICAL,
  795. "[DM] RtlDosPathNameToRelativeNtPathName_U failed\n");
  796. return ERROR_INVALID_PARAMETER;
  797. }
  798. FreeBuffer = FileName.Buffer;
  799. if (RelativeName.RelativeName.Length) {
  800. FileName = RelativeName.RelativeName;
  801. } else {
  802. RelativeName.ContainingDirectory = NULL;
  803. }
  804. InitializeObjectAttributes(&SourceFile,
  805. &FileName,
  806. OBJ_CASE_INSENSITIVE,
  807. RelativeName.ContainingDirectory,
  808. NULL);
  809. Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  810. &WasEnabled);
  811. if (Status != ERROR_SUCCESS) {
  812. if (Status == STATUS_PRIVILEGE_NOT_HELD) {
  813. ClRtlLogPrint(LOG_CRITICAL,
  814. "[DM] Restore privilege not held by cluster service\n");
  815. } else {
  816. ClRtlLogPrint(LOG_CRITICAL,
  817. "[DM] Attempt to enable restore privilege failed %1!lx!\n",Status);
  818. }
  819. } else {
  820. //
  821. // Note : Sunitas
  822. // There used to be a registry bug where if we set REG_NO_LAZY_FLUSH and the hive
  823. // is corrupt, the system crashes. So we used to first try loading it without the
  824. // REG_NO_LAZY_FLUSH. If that works, unload it and do it again with
  825. // REG_NO_LAZY_FLUSH. The registry folks claim that is fixed..so I am
  826. // removing that hack
  827. //
  828. Status = NtLoadKey2((POBJECT_ATTRIBUTES)&RegistryMachineClusterObja,
  829. &SourceFile,
  830. REG_NO_LAZY_FLUSH);
  831. if (Status != STATUS_SUCCESS)
  832. {
  833. ClRtlLogPrint(LOG_CRITICAL,
  834. "[DM] DmpLoadHive: NtLoadKey2 failed with error, %1!u!\n",
  835. Status);
  836. CL_UNEXPECTED_ERROR(Status);
  837. }
  838. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  839. WasEnabled);
  840. }
  841. RtlReleaseRelativeName(&RelativeName);
  842. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  843. return(Status);
  844. }
  845. DWORD DmpUnloadHive()
  846. /*++
  847. Routine Description:
  848. Unloads the cluster database from HKLM\Cluster. This is called at initialization
  849. to make sure that the database is loaded with the correct flags.
  850. Return Value:
  851. ERROR_SUCCESS if successful
  852. Win32 error code otherwise
  853. --*/
  854. {
  855. BOOLEAN WasEnabled;
  856. NTSTATUS Status;
  857. ClRtlLogPrint(LOG_NOISE,
  858. "[DM] DmpUnloadHive: unloading the hive\r\n");
  859. Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  860. &WasEnabled);
  861. if (Status != ERROR_SUCCESS)
  862. {
  863. if (Status == STATUS_PRIVILEGE_NOT_HELD)
  864. {
  865. ClRtlLogPrint(LOG_CRITICAL,
  866. "[DM] DmpUnloadHive:: Restore privilege not held by cluster service\n");
  867. }
  868. else
  869. {
  870. ClRtlLogPrint(LOG_CRITICAL,
  871. "[DM] DmpUnloadHive: Attempt to enable restore privilege failed %1!lx!\n",Status);
  872. }
  873. goto FnExit;
  874. }
  875. Status = NtUnloadKey((POBJECT_ATTRIBUTES)&RegistryMachineClusterObja);
  876. if (Status != STATUS_SUCCESS)
  877. {
  878. ClRtlLogPrint(LOG_CRITICAL,
  879. "[DM] DmpUnloadHive: NtUnloadKey failed with error, %1!u!\n",
  880. Status);
  881. CL_UNEXPECTED_ERROR(Status);
  882. }
  883. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  884. WasEnabled);
  885. FnExit:
  886. return(Status);
  887. }
  888. DWORD
  889. DmpSafeDatabaseCopy(
  890. IN LPCWSTR FileName,
  891. IN LPCWSTR Path,
  892. IN LPCWSTR BkpPath,
  893. IN BOOL bDeleteSrcFile
  894. )
  895. /*++
  896. Routine Description:
  897. Loads the cluster database into HKLM\Cluster
  898. Arguments:
  899. FileName - Supplies the fully qualified filename of the new cluster database
  900. Path - Supplies the fully qualified filename of the cluster database.
  901. BkpPath - Supplies the fully qualified filename of the cluster database temporary
  902. backup
  903. bDeleteSrcFile - Specifies whether the source file may be deleted
  904. Return Value:
  905. ERROR_SUCCESS if successful
  906. Win32 error code otherwise
  907. --*/
  908. {
  909. DWORD dwStatus = ERROR_SUCCESS;
  910. //set the file attributes of the bkp file to be normal so that we can
  911. //overwrite it if it exists
  912. if (!QfsSetFileAttributes(BkpPath, FILE_ATTRIBUTE_NORMAL))
  913. {
  914. ClRtlLogPrint(LOG_UNUSUAL,
  915. "[DM] DmpSafeDatabaseCopy:: SetFileAttrib on BkpPath %1!ws! failed, Status=%2!u!\n",
  916. BkpPath, GetLastError());
  917. //this may fail because the file doesnt exist but that is not fatal so we ignore the error
  918. }
  919. //Save the database to a temp database that can be used for recovery
  920. //ClRtlCopyFileAndFlushBuffers preserves attributes of the old file
  921. if (!QfsClRtlCopyFileAndFlushBuffers(Path, BkpPath))
  922. {
  923. dwStatus = GetLastError();
  924. ClRtlLogPrint(LOG_CRITICAL,
  925. "[DM] DmpSafeDatabaseCopy:: Failed to create a backup copy of database, Status=%1!u!\n",
  926. dwStatus);
  927. goto FnExit;
  928. }
  929. //hide the file since users are not supposed to know about it
  930. if (!QfsSetFileAttributes(BkpPath, FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY))
  931. {
  932. dwStatus = GetLastError();
  933. ClRtlLogPrint(LOG_CRITICAL,
  934. "[DM] DmpSafeDatabaseCopy:: SetFileAttrib on BkpPath %1!ws! failed, Status=%2!u!\n",
  935. BkpPath, dwStatus);
  936. goto FnExit;
  937. }
  938. //set DatabaseCopyInProgress key to be TRUE
  939. dwStatus = DmpSetDwordInClusterServer( L"ClusterDatabaseCopyInProgress",1);
  940. if (dwStatus != ERROR_SUCCESS)
  941. {
  942. ClRtlLogPrint(LOG_CRITICAL,
  943. "[DM] DmpSafeDatabaseCopy:: Failed to set ClusterDatabaseCopyInProgress, Status=%1!u!\n",
  944. dwStatus);
  945. goto FnExit;
  946. }
  947. //delete clusdb
  948. if (!QfsDeleteFile(Path))
  949. {
  950. ClRtlLogPrint(LOG_UNUSUAL,
  951. "[DM] DmpSafeDatabaseCopy:: Couldnt delete the database file, Error=%1!u!\n",
  952. GetLastError());
  953. //this is not fatal, we will still try the move file
  954. }
  955. //copy the new database to clusdb
  956. if (bDeleteSrcFile)
  957. {
  958. //the source file may be deleted, this is true at join sync time
  959. //the source file is a temporary file
  960. if (!QfsMoveFileEx(FileName, Path, MOVEFILE_REPLACE_EXISTING |
  961. MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH))
  962. {
  963. dwStatus = GetLastError();
  964. ClRtlLogPrint(LOG_NOISE,
  965. "[DM] DmpSafeDatabaseCopy:: Failed to move %1!ws! to %2!ws!, Status=%3!u!\n",
  966. FileName, Path, dwStatus);
  967. goto FnExit;
  968. }
  969. }
  970. else
  971. {
  972. //the source file must not be deleted use copy..this is true
  973. //when the logs are being rolled at form and we are uploading
  974. //the database from a checkpoint file
  975. if (!QfsClRtlCopyFileAndFlushBuffers(FileName, Path))
  976. {
  977. dwStatus = GetLastError();
  978. ClRtlLogPrint(LOG_CRITICAL,
  979. "[DM] DmpSafeDatabaseCopy:: Failed to copy %1!ws! to %2!ws!, Status=%3!u!\n",
  980. FileName, Path, dwStatus);
  981. goto FnExit;
  982. }
  983. }
  984. //set databaseCopyInProgress key to FALSE
  985. dwStatus = DmpSetDwordInClusterServer( L"ClusterDatabaseCopyInProgress", 0);
  986. if (dwStatus != ERROR_SUCCESS)
  987. {
  988. ClRtlLogPrint(LOG_NOISE,
  989. "[DM] DmpSafeDatabaseCopy:: Failed to set ClusterDatabaseCopyInProgress, Status=%1!u!\n",
  990. dwStatus);
  991. goto FnExit;
  992. }
  993. //now that clusdb is safely copied, we can delete the backup
  994. //for that we need to set the file attribute to normal
  995. if (!QfsSetFileAttributes(BkpPath, FILE_ATTRIBUTE_NORMAL))
  996. {
  997. ClRtlLogPrint(LOG_CRITICAL,
  998. "[DM] DmpSafeDatabaseCopy:: SetFileAttrib on BkpPath %1!ws! failed, Status=%2!u!\n",
  999. BkpPath, GetLastError());
  1000. }
  1001. //delete the backup
  1002. if (!QfsDeleteFile(BkpPath))
  1003. {
  1004. ClRtlLogPrint(LOG_NOISE,
  1005. "[DM] DmpSafeDatabaseCopy:: Failed to delete bkp database file %1!ws!, Status=%2!u!\n",
  1006. BkpPath, GetLastError());
  1007. //this is not fatal so ignore the error
  1008. }
  1009. FnExit:
  1010. return(dwStatus);
  1011. }
  1012. DWORD
  1013. DmpSetDwordInClusterServer(
  1014. LPCWSTR lpszValueName,
  1015. DWORD dwValue
  1016. )
  1017. /*++
  1018. Routine Description:
  1019. Sets the value specified under
  1020. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Cluster Server",
  1021. to the value specified by dwValue. It flushes the change.
  1022. Arguments:
  1023. lpszValueName : Sets the value for the name specified by lpszValueName
  1024. dwValue : The value to set to.
  1025. Return Value:
  1026. ERROR_SUCCESS if everything worked ok
  1027. --*/
  1028. {
  1029. HKEY hKey;
  1030. DWORD dwStatus = ERROR_SUCCESS; // returned by registry API functions
  1031. // Attempt to open an existing key in the registry.
  1032. dwStatus = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  1033. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Cluster Server",
  1034. 0, // reserved
  1035. KEY_WRITE,
  1036. &hKey );
  1037. // Was the registry key opened successfully ?
  1038. if ( dwStatus == ERROR_SUCCESS )
  1039. {
  1040. DWORD dwValueType = REG_DWORD;
  1041. DWORD dwDataBufferSize = sizeof( DWORD );
  1042. dwStatus = RegSetValueExW( hKey,
  1043. lpszValueName,
  1044. 0, // reserved
  1045. dwValueType,
  1046. (LPBYTE) &dwValue,
  1047. dwDataBufferSize );
  1048. //Flush the key
  1049. RegFlushKey(hKey);
  1050. // Close the registry key.
  1051. RegCloseKey( hKey );
  1052. // Was the value set successfully?
  1053. }
  1054. return(dwStatus);
  1055. } // DmpSetDwordInClusterServer
  1056. DWORD DmpGetDwordFromClusterServer(
  1057. IN LPCWSTR lpszValueName,
  1058. OUT LPDWORD pdwValue,
  1059. IN DWORD dwDefaultValue
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. Gets the DWORD value specified in lpszValueName.
  1064. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Cluster Server".
  1065. If the value doesnt exist, the default is returned.
  1066. Arguments:
  1067. lpszValueName : The Value to read.
  1068. pdwValue : Returns the value of the key specified by lpszValueName
  1069. dwDefaultValue: The value to be returned if the specified key doesnt exist
  1070. or in case of error.
  1071. Return Value:
  1072. ERROR_SUCCESS if everything worked ok or if the key wasnt present.
  1073. --*/
  1074. {
  1075. HKEY hKey = NULL;
  1076. DWORD dwStatus; // returned by registry API functions
  1077. DWORD dwClusterInstallState;
  1078. DWORD dwValueType;
  1079. DWORD dwDataBufferSize = sizeof( DWORD );
  1080. *pdwValue = dwDefaultValue;
  1081. // Read the registry key that indicates whether cluster files are installed.
  1082. dwStatus = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  1083. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Cluster Server",
  1084. 0, // reserved
  1085. KEY_READ,
  1086. &hKey );
  1087. // Was the registry key opened successfully ?
  1088. if ( dwStatus != ERROR_SUCCESS )
  1089. {
  1090. if ( dwStatus == ERROR_FILE_NOT_FOUND )
  1091. {
  1092. *pdwValue = dwDefaultValue;
  1093. dwStatus = ERROR_SUCCESS;
  1094. goto FnExit;
  1095. }
  1096. }
  1097. // Read the entry.
  1098. dwStatus = RegQueryValueExW( hKey,
  1099. lpszValueName,
  1100. 0, // reserved
  1101. &dwValueType,
  1102. (LPBYTE) pdwValue,
  1103. &dwDataBufferSize );
  1104. // Was the value read successfully ?
  1105. if ( dwStatus != ERROR_SUCCESS )
  1106. {
  1107. if ( dwStatus == ERROR_FILE_NOT_FOUND )
  1108. {
  1109. *pdwValue = dwDefaultValue;
  1110. dwStatus = ERROR_SUCCESS;
  1111. goto FnExit;
  1112. }
  1113. }
  1114. FnExit:
  1115. // Close the registry key.
  1116. if ( hKey )
  1117. {
  1118. RegCloseKey( hKey );
  1119. }
  1120. return ( dwStatus );
  1121. } //*** DmpGetDwordFromClusterServer