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.

4497 lines
122 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. resutils.c
  5. Abstract:
  6. Common utility routines for clusters resources
  7. Author:
  8. John Vert (jvert) 12/15/1996
  9. Revision History:
  10. --*/
  11. #pragma warning( push )
  12. #pragma warning( disable : 4115 ) // Clusrtl - struct def in parentheses
  13. #pragma warning( disable : 4201 ) // SDK - nameless struct/union
  14. #include "clusres.h"
  15. #include "clusrtl.h"
  16. #include "winbase.h"
  17. #include <windows.h>
  18. #include "userenv.h"
  19. #include <strsafe.h>
  20. #pragma warning( push )
  21. #pragma warning( disable: 4214 )
  22. #include <windns.h>
  23. #pragma warning( pop )
  24. #pragma warning( pop )
  25. //
  26. // For some reason this doesn't get pulled in from winnt.h.
  27. //
  28. #ifndef RTL_NUMBER_OF
  29. #define RTL_NUMBER_OF(A) (sizeof(A)/sizeof((A)[0]))
  30. #endif
  31. //#define DBG_PRINT printf
  32. #define DBG_PRINT
  33. typedef struct _WORK_CONTEXT {
  34. PCLUS_WORKER Worker;
  35. PVOID lpParameter;
  36. PWORKER_START_ROUTINE lpStartRoutine;
  37. } WORK_CONTEXT, *PWORK_CONTEXT;
  38. //
  39. // Local Data
  40. //
  41. CRITICAL_SECTION ResUtilWorkerLock;
  42. BOOLEAN
  43. WINAPI
  44. ResUtilDllEntry(
  45. IN HINSTANCE DllHandle,
  46. IN DWORD Reason,
  47. IN LPVOID Reserved
  48. )
  49. /*++
  50. Routine Description:
  51. Main DLL entry for resource utility helper module.
  52. Arguments:
  53. DllHandle - Supplies the DLL Handle.
  54. Reason - Supplies the call reason.
  55. Return Value:
  56. TRUE if successful
  57. FALSE if unsuccessful
  58. --*/
  59. {
  60. BOOLEAN fSuccess = TRUE;
  61. UNREFERENCED_PARAMETER( Reserved );
  62. if ( Reason == DLL_PROCESS_ATTACH )
  63. {
  64. fSuccess = (BOOLEAN) ( InitializeCriticalSectionAndSpinCount(&ResUtilWorkerLock,1000) != 0 ) ? TRUE : FALSE;
  65. DisableThreadLibraryCalls(DllHandle);
  66. }
  67. if ( Reason == DLL_PROCESS_DETACH )
  68. {
  69. DeleteCriticalSection(&ResUtilWorkerLock);
  70. }
  71. return fSuccess;
  72. } // ResUtilDllEntry
  73. DWORD
  74. WINAPI
  75. ResUtilStartResourceService(
  76. IN LPCWSTR pszServiceName,
  77. OUT LPSC_HANDLE phServiceHandle
  78. )
  79. /*++
  80. Routine Description:
  81. Start a service.
  82. Arguments:
  83. pszServiceName - The name of the service to start.
  84. phServiceHandle - Pointer to a handle to receive the service handle
  85. for this service.
  86. Return Value:
  87. ERROR_SUCCESS if successful.
  88. A Win32 error code on failure.
  89. --*/
  90. {
  91. SC_HANDLE serviceHandle;
  92. SC_HANDLE scManagerHandle;
  93. DWORD status = ERROR_SUCCESS;
  94. SERVICE_STATUS serviceStatus;
  95. scManagerHandle = OpenSCManager( NULL, // local machine
  96. NULL, // ServicesActive database
  97. SC_MANAGER_ALL_ACCESS ); // all access
  98. if ( scManagerHandle == NULL ) {
  99. status = GetLastError();
  100. DBG_PRINT( "ResUtilStartResourceService: Cannot access service controller! Error: %u.\n",
  101. status );
  102. return(status);
  103. }
  104. serviceHandle = OpenService( scManagerHandle,
  105. pszServiceName,
  106. SERVICE_ALL_ACCESS );
  107. if ( serviceHandle == NULL ) {
  108. status = GetLastError();
  109. DBG_PRINT( "ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n",
  110. pszServiceName,
  111. status );
  112. CloseServiceHandle( scManagerHandle );
  113. return(status);
  114. }
  115. CloseServiceHandle( scManagerHandle );
  116. if ( !StartService( serviceHandle,
  117. 0,
  118. NULL) ) {
  119. status = GetLastError();
  120. if ( status == ERROR_SERVICE_ALREADY_RUNNING ) {
  121. status = ERROR_SUCCESS;
  122. } else {
  123. DBG_PRINT( "ResUtilStartResourceService: Failed to start %ws service. Error: %u.\n",
  124. pszServiceName,
  125. status );
  126. }
  127. } else {
  128. //
  129. // Wait for the service to start.
  130. //
  131. for (;;)
  132. {
  133. status = ERROR_SUCCESS;
  134. if ( !QueryServiceStatus(serviceHandle, &serviceStatus) ) {
  135. status = GetLastError();
  136. DBG_PRINT("ResUtilStartResourceService: Failed to query status of %ws service. Error: %u.\n",
  137. pszServiceName,
  138. status);
  139. break;
  140. }
  141. if ( serviceStatus.dwCurrentState == SERVICE_RUNNING ) {
  142. break;
  143. } else if ( serviceStatus.dwCurrentState != SERVICE_START_PENDING ) {
  144. status = ERROR_SERVICE_NEVER_STARTED;
  145. DBG_PRINT("ResUtilStartResourceService: Failed to start %ws service. CurrentState: %u.\n",
  146. pszServiceName,
  147. serviceStatus.dwCurrentState);
  148. break;
  149. }
  150. Sleep(200); // Try again in a little bit
  151. } // for: ever
  152. } // else:
  153. if ( (status == ERROR_SUCCESS) &&
  154. ARGUMENT_PRESENT(phServiceHandle) ) {
  155. *phServiceHandle = serviceHandle;
  156. } else {
  157. CloseServiceHandle( serviceHandle );
  158. }
  159. return(status);
  160. } // ResUtilStartResourceService
  161. DWORD
  162. WINAPI
  163. ResUtilStopResourceService(
  164. IN LPCWSTR pszServiceName
  165. )
  166. /*++
  167. Routine Description:
  168. Stop a service.
  169. Arguments:
  170. pszServiceName - The name of the service to stop.
  171. Return Value:
  172. ERROR_SUCCESS - Service stopped successfully.
  173. Win32 error code - Error stopping service.
  174. --*/
  175. {
  176. SC_HANDLE serviceHandle = NULL;
  177. SC_HANDLE scManagerHandle = NULL;
  178. DWORD sc = ERROR_SUCCESS;
  179. int retryTime = 30*1000; // wait 30 secs for shutdown
  180. int retryTick = 300; // 300 msec at a time
  181. BOOL didStop = FALSE;
  182. SERVICE_STATUS serviceStatus;
  183. scManagerHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  184. if ( scManagerHandle == NULL )
  185. {
  186. sc = GetLastError();
  187. DBG_PRINT( "ResUtilStartResourceService: Cannot access service controller! Error: %u.\n", sc );
  188. goto Cleanup;
  189. }
  190. serviceHandle = OpenService( scManagerHandle, pszServiceName, SERVICE_ALL_ACCESS );
  191. if ( serviceHandle == NULL )
  192. {
  193. sc = GetLastError();
  194. DBG_PRINT( "ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n", pszServiceName, sc );
  195. CloseServiceHandle(scManagerHandle);
  196. goto Cleanup;
  197. }
  198. CloseServiceHandle(scManagerHandle);
  199. for (;;)
  200. {
  201. sc = ERROR_SUCCESS;
  202. if ( !ControlService(serviceHandle,
  203. (didStop ? SERVICE_CONTROL_INTERROGATE : SERVICE_CONTROL_STOP),
  204. &serviceStatus) ) {
  205. sc = GetLastError();
  206. if ( sc == ERROR_SUCCESS )
  207. {
  208. didStop = TRUE;
  209. if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
  210. {
  211. DBG_PRINT( "ResUtilStartResourceService: service %ws successfully stopped.\n", pszServiceName );
  212. goto Cleanup;
  213. }
  214. }
  215. }
  216. if ( (sc == ERROR_EXCEPTION_IN_SERVICE) ||
  217. (sc == ERROR_PROCESS_ABORTED) ||
  218. (sc == ERROR_SERVICE_NOT_ACTIVE) )
  219. {
  220. DBG_PRINT( "ResUtilStartResourceService: service %ws stopped or died; sc = %u.\n", pszServiceName, sc );
  221. sc = ERROR_SUCCESS;
  222. goto Cleanup;
  223. }
  224. if ( (retryTime -= retryTick) <= 0 )
  225. {
  226. DBG_PRINT( "ResUtilStartResourceService: service %ws did not stop; giving up.\n", pszServiceName, sc );
  227. sc = ERROR_TIMEOUT;
  228. goto Cleanup;
  229. }
  230. DBG_PRINT("ResUtilStartResourceService: StopResourceService retrying...\n");
  231. Sleep(retryTick);
  232. } // for: ever
  233. Cleanup:
  234. CloseServiceHandle( scManagerHandle );
  235. CloseServiceHandle( serviceHandle );
  236. return sc;
  237. } // ResUtilStopResourceService
  238. DWORD
  239. WINAPI
  240. ResUtilVerifyResourceService(
  241. IN LPCWSTR pszServiceName
  242. )
  243. /*++
  244. Routine Description:
  245. Verify that a service is alive.
  246. Arguments:
  247. pszServiceName - The name of the service to verify.
  248. Return Value:
  249. ERROR_SUCCESS - Service is alive.
  250. Win32 error code - Error verifying service, or service is not alive.
  251. --*/
  252. {
  253. BOOL success;
  254. SC_HANDLE serviceHandle;
  255. SC_HANDLE scManagerHandle;
  256. DWORD status = ERROR_SUCCESS;
  257. SERVICE_STATUS serviceStatus;
  258. scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  259. if ( scManagerHandle == NULL ) {
  260. status = GetLastError();
  261. DBG_PRINT("ResUtilStartResourceService: Cannot access service controller! Error: %u.\n",
  262. status);
  263. return(status);
  264. }
  265. serviceHandle = OpenService( scManagerHandle,
  266. pszServiceName,
  267. SERVICE_QUERY_STATUS );
  268. if ( serviceHandle == NULL ) {
  269. status = GetLastError();
  270. DBG_PRINT("ResUtilStartResourceService: Cannot open service %ws. Error: %u.\n",
  271. pszServiceName,
  272. status);
  273. CloseServiceHandle(scManagerHandle);
  274. return(status);
  275. }
  276. CloseServiceHandle(scManagerHandle);
  277. success = QueryServiceStatus( serviceHandle,
  278. &serviceStatus );
  279. status = GetLastError();
  280. CloseServiceHandle(serviceHandle);
  281. if ( !success ) {
  282. DBG_PRINT("ResUtilStartResourceService: Cannot query service %ws. Error: %u.\n",
  283. pszServiceName,
  284. status);
  285. return(status);
  286. }
  287. if ( (serviceStatus.dwCurrentState != SERVICE_RUNNING) &&
  288. (serviceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
  289. DBG_PRINT("ResUtilStartResourceService: Service %ws is not alive: dwCurrentState: %u.\n",
  290. pszServiceName,
  291. serviceStatus.dwCurrentState);
  292. return(ERROR_SERVICE_NOT_ACTIVE);
  293. }
  294. return(ERROR_SUCCESS);
  295. } // ResUtilVerifyResourceService
  296. DWORD
  297. WINAPI
  298. ResUtilStopService(
  299. IN SC_HANDLE hServiceHandle
  300. )
  301. /*++
  302. Routine Description:
  303. Stop a service.
  304. Arguments:
  305. hServiceHandle - The handle of the service to stop.
  306. Return Value:
  307. ERROR_SUCCESS - Service stopped successfully.
  308. Win32 error code - Error stopping service.
  309. Notes:
  310. The hServiceHandle is closed as a side effect of this routine.
  311. --*/
  312. {
  313. DWORD status = ERROR_SUCCESS;
  314. DWORD retryTime = 30*1000; // wait 30 secs for shutdown
  315. DWORD retryTick = 300; // 300 msec at a time
  316. BOOL didStop = FALSE;
  317. SERVICE_STATUS serviceStatus;
  318. for (;;)
  319. {
  320. status = ERROR_SUCCESS;
  321. if ( !ControlService(hServiceHandle,
  322. (didStop ? SERVICE_CONTROL_INTERROGATE : SERVICE_CONTROL_STOP),
  323. &serviceStatus) ) {
  324. status = GetLastError();
  325. if ( status == ERROR_SUCCESS ) {
  326. didStop = TRUE;
  327. if ( serviceStatus.dwCurrentState == SERVICE_STOPPED ) {
  328. DBG_PRINT("ResUtilStartResourceService: service successfully stopped.\n" );
  329. break;
  330. }
  331. }
  332. }
  333. if ( (status == ERROR_EXCEPTION_IN_SERVICE) ||
  334. (status == ERROR_PROCESS_ABORTED) ||
  335. (status == ERROR_SERVICE_NOT_ACTIVE) ) {
  336. DBG_PRINT("ResUtilStartResourceService: service stopped or died; status = %u.\n",
  337. status);
  338. status = ERROR_SUCCESS;
  339. break;
  340. }
  341. if ( (retryTime -= retryTick) <= 0 ) {
  342. DBG_PRINT("ResUtilStartResourceService: service did not stop; giving up.\n",
  343. status);
  344. status = ERROR_TIMEOUT;
  345. break;
  346. }
  347. DBG_PRINT("ResUtilStartResourceService: StopResourceService retrying...\n");
  348. Sleep(retryTick);
  349. } // for: ever
  350. CloseServiceHandle(hServiceHandle);
  351. return(status);
  352. } // ResUtilStopResourceService
  353. DWORD
  354. WINAPI
  355. ResUtilVerifyService(
  356. IN SC_HANDLE hServiceHandle
  357. )
  358. /*++
  359. Routine Description:
  360. Verify that a service is alive.
  361. Arguments:
  362. hServiceHandle - The handle of the service to verify.
  363. Return Value:
  364. ERROR_SUCCESS - Service is alive.
  365. Win32 error code - Error verifying service, or service is not alive.
  366. --*/
  367. {
  368. BOOL success;
  369. DWORD status = ERROR_SUCCESS;
  370. SERVICE_STATUS serviceStatus;
  371. success = QueryServiceStatus( hServiceHandle,
  372. &serviceStatus );
  373. if ( !success ) {
  374. status = GetLastError();
  375. DBG_PRINT("ResUtilStartResourceService: Cannot query service. Error: %u.\n",
  376. status);
  377. return(status);
  378. }
  379. if ( (serviceStatus.dwCurrentState != SERVICE_RUNNING) &&
  380. (serviceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
  381. DBG_PRINT("ResUtilStartResourceService: Service is not alive: dwCurrentState: %u.\n",
  382. serviceStatus.dwCurrentState);
  383. return(ERROR_SERVICE_NOT_ACTIVE);
  384. }
  385. return(ERROR_SUCCESS);
  386. } // ResUtilVerifyService
  387. /////////////////////////////////////////////////////////////////////////////
  388. //++
  389. //
  390. // ResUtilTerminateServiceProcessFromResDll
  391. //
  392. // Description:
  393. // Attempt to terminate a service process from a resource DLL.
  394. //
  395. // Arguments:
  396. // dwServicePid [IN]
  397. // The process ID of the service process to terminate.
  398. //
  399. // bOffline [IN]
  400. // TRUE = called from the offline thread.
  401. //
  402. // pdwResourceState [OUT]
  403. // State of the resource. Optional.
  404. //
  405. // pfnLogEvent [IN]
  406. // Pointer to a routine that handles the reporting of events from
  407. // the resource DLL.
  408. //
  409. // hResourceHandle [IN]
  410. // Handle for logging.
  411. //
  412. // Return Value:
  413. // ERROR_SUCCESS
  414. // The function completed successfully.
  415. //
  416. // Win32 error code
  417. // The function failed.
  418. //
  419. //--
  420. /////////////////////////////////////////////////////////////////////////////
  421. DWORD
  422. WINAPI
  423. ResUtilTerminateServiceProcessFromResDll(
  424. IN DWORD dwServicePid,
  425. IN BOOL bOffline,
  426. OUT PDWORD pdwResourceState,
  427. IN PLOG_EVENT_ROUTINE pfnLogEvent,
  428. IN RESOURCE_HANDLE hResourceHandle
  429. )
  430. {
  431. DWORD sc = ERROR_SUCCESS;
  432. HANDLE hSvcProcess = NULL;
  433. BOOLEAN bWasEnabled;
  434. DWORD dwResourceState = ClusterResourceFailed;
  435. (pfnLogEvent)(
  436. hResourceHandle,
  437. LOG_INFORMATION,
  438. L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! might be terminated...\n",
  439. dwServicePid
  440. );
  441. //
  442. // Adjust the privilege to allow debug. This is to allow termination
  443. // of a service process which runs in a local system account from a
  444. // different service process which runs in a domain user account.
  445. //
  446. sc = ClRtlEnableThreadPrivilege(
  447. SE_DEBUG_PRIVILEGE,
  448. &bWasEnabled
  449. );
  450. if ( sc != ERROR_SUCCESS )
  451. {
  452. (pfnLogEvent)(
  453. hResourceHandle,
  454. LOG_ERROR,
  455. L"ResUtilTerminateServiceProcessFromResDll: Unable to set debug privilege for process with id=%1!u!, status=%2!u!...\n",
  456. dwServicePid,
  457. sc
  458. );
  459. goto Cleanup;
  460. } // if: error enabling thread privilege
  461. //
  462. // Open the process so we can terminate it.
  463. //
  464. hSvcProcess = OpenProcess(
  465. PROCESS_TERMINATE,
  466. FALSE,
  467. dwServicePid
  468. );
  469. if ( hSvcProcess == NULL )
  470. {
  471. //
  472. // Did this happen because the process terminated
  473. // too quickly after we sent out one control request ?
  474. //
  475. sc = GetLastError();
  476. (pfnLogEvent)(
  477. hResourceHandle,
  478. LOG_INFORMATION,
  479. L"ResUtilTerminateServiceProcessFromResDll: Unable to open pid=%1!u! for termination, status=%2!u!...\n",
  480. dwServicePid,
  481. sc
  482. );
  483. } // if: error opening the process
  484. else
  485. {
  486. if ( ! bOffline )
  487. {
  488. (pfnLogEvent)(
  489. hResourceHandle,
  490. LOG_INFORMATION,
  491. L"ResUtilTerminateServiceProcessFromResDll: Pid=%1!u! will be terminated by brute force...\n",
  492. dwServicePid
  493. );
  494. } // if: called from Terminate
  495. else
  496. {
  497. //
  498. // Wait 3 seconds for the process to shutdown gracefully.
  499. //
  500. if ( WaitForSingleObject( hSvcProcess, 3000 )
  501. == WAIT_OBJECT_0 )
  502. {
  503. (pfnLogEvent)(
  504. hResourceHandle,
  505. LOG_INFORMATION,
  506. L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! shutdown gracefully...\n",
  507. dwServicePid
  508. );
  509. dwResourceState = ClusterResourceOffline;
  510. sc = ERROR_SUCCESS;
  511. goto RestoreAndCleanup;
  512. } // if: process exited on its own
  513. } // else: called from Offline
  514. if ( ! TerminateProcess( hSvcProcess, 0 ) )
  515. {
  516. sc = GetLastError();
  517. (pfnLogEvent)(
  518. hResourceHandle,
  519. LOG_ERROR,
  520. L"ResUtilTerminateServiceProcessFromResDll: Unable to terminate process with id=%1!u!, status=%2!u!...\n",
  521. dwServicePid,
  522. sc
  523. );
  524. } // if: error terminating the process
  525. else
  526. {
  527. (pfnLogEvent)(
  528. hResourceHandle,
  529. LOG_INFORMATION,
  530. L"ResUtilTerminateServiceProcessFromResDll: Process with id=%1!u! was terminated...\n",
  531. dwServicePid
  532. );
  533. dwResourceState = ClusterResourceOffline;
  534. } // else: process terminated successfully
  535. } // else: process opened successfully
  536. RestoreAndCleanup:
  537. ClRtlRestoreThreadPrivilege(
  538. SE_DEBUG_PRIVILEGE,
  539. bWasEnabled
  540. );
  541. Cleanup:
  542. if ( hSvcProcess != NULL )
  543. {
  544. CloseHandle( hSvcProcess );
  545. } // if: process was opened successfully
  546. if ( pdwResourceState != NULL )
  547. {
  548. *pdwResourceState = dwResourceState;
  549. } // if: caller wants the resource state
  550. (pfnLogEvent)(
  551. hResourceHandle,
  552. LOG_INFORMATION,
  553. L"ResUtilTerminateServiceProcessFromResDll: Process id=%1!u!, status=%2!u!, state=%3!u!.\n",
  554. dwServicePid,
  555. sc,
  556. dwResourceState
  557. );
  558. return sc;
  559. } //*** ResUtilTerminateServiceProcessFromResDll()
  560. LPWSTR
  561. WINAPI
  562. ResUtilDupString(
  563. IN LPCWSTR pszInString
  564. )
  565. /*++
  566. Routine Description:
  567. Duplicates a string.
  568. Arguments:
  569. pszInString - Supplies the string to be duplicated.
  570. Return Value:
  571. A pointer to a buffer containing the duplicate if successful.
  572. NULL if unsuccessful. Call GetLastError() to get more details.
  573. --*/
  574. {
  575. PWSTR pszNewString = NULL;
  576. size_t cbString;
  577. DWORD sc = ERROR_SUCCESS;
  578. HRESULT hr;
  579. //
  580. // Get the size of the parameter so we know how much to allocate.
  581. //
  582. cbString = (wcslen( pszInString ) + 1) * sizeof(WCHAR);
  583. //
  584. // Allocate a buffer to copy the string into.
  585. //
  586. pszNewString = (PWSTR) LocalAlloc( LMEM_FIXED, cbString );
  587. if ( pszNewString == NULL )
  588. {
  589. sc = ERROR_NOT_ENOUGH_MEMORY;
  590. goto Cleanup;
  591. }
  592. //
  593. // Copy the in string to the new string.
  594. //
  595. hr = StringCbCopyW( pszNewString, cbString, pszInString );
  596. if ( FAILED( hr ) )
  597. {
  598. sc = HRESULT_CODE( hr );
  599. goto Cleanup;
  600. }
  601. Cleanup:
  602. if ( sc != ERROR_SUCCESS )
  603. {
  604. LocalFree( pszNewString );
  605. pszNewString = NULL;
  606. }
  607. SetLastError( sc );
  608. return pszNewString;
  609. } // ResUtilDupString
  610. DWORD
  611. WINAPI
  612. ResUtilGetBinaryValue(
  613. IN HKEY hkeyClusterKey,
  614. IN LPCWSTR pszValueName,
  615. OUT LPBYTE * ppbOutValue,
  616. OUT LPDWORD pcbOutValueSize
  617. )
  618. /*++
  619. Routine Description:
  620. Queries a REG_BINARY or REG_MULTI_SZ value out of the cluster
  621. database and allocates the necessary storage for it.
  622. Arguments:
  623. hkeyClusterKey - Supplies the cluster key where the value is stored
  624. pszValueName - Supplies the name of the value.
  625. ppbOutValue - Supplies the address of a pointer in which to return the value.
  626. pcbOutValueSize - Supplies the address of a DWORD in which to return the
  627. size of the value.
  628. Return Value:
  629. ERROR_SUCCESS - The value was read successfully.
  630. ERROR_NOT_ENOUGH_MEMORY - Error allocating memory for the value.
  631. Win32 error code - The operation failed.
  632. --*/
  633. {
  634. LPBYTE value;
  635. DWORD valueSize;
  636. DWORD valueType;
  637. DWORD status;
  638. //
  639. // Initialize the output parameters.
  640. //
  641. *ppbOutValue = NULL;
  642. *pcbOutValueSize = 0;
  643. //
  644. // Get the size of the value so we know how much to allocate.
  645. //
  646. valueSize = 0;
  647. status = ClusterRegQueryValue( hkeyClusterKey,
  648. pszValueName,
  649. &valueType,
  650. NULL,
  651. &valueSize );
  652. if ( (status != ERROR_SUCCESS) &&
  653. (status != ERROR_MORE_DATA) ) {
  654. return(status);
  655. }
  656. //
  657. // Allocate a buffer to read the value into.
  658. //
  659. value = LocalAlloc( LMEM_FIXED, valueSize );
  660. if ( value == NULL ) {
  661. return(ERROR_NOT_ENOUGH_MEMORY);
  662. }
  663. //
  664. // Read the value from the cluster database.
  665. //
  666. status = ClusterRegQueryValue( hkeyClusterKey,
  667. pszValueName,
  668. &valueType,
  669. (LPBYTE)value,
  670. &valueSize );
  671. if ( status != ERROR_SUCCESS ) {
  672. LocalFree( value );
  673. } else {
  674. *ppbOutValue = value;
  675. *pcbOutValueSize = valueSize;
  676. }
  677. return(status);
  678. } // ResUtilGetBinaryValue
  679. PWSTR
  680. WINAPI
  681. ResUtilGetSzValue(
  682. IN HKEY hkeyClusterKey,
  683. IN LPCWSTR pszValueName
  684. )
  685. /*++
  686. Routine Description:
  687. Queries a REG_SZ or REG_EXPAND_SZ value out of the cluster database
  688. and allocates the necessary storage for it.
  689. Arguments:
  690. hkeyClusterKey - Supplies the cluster key where the value is stored
  691. pszValueName - Supplies the name of the value.
  692. Return Value:
  693. A pointer to a buffer containing the value if successful.
  694. NULL if unsuccessful. Call GetLastError() to get more details.
  695. --*/
  696. {
  697. PWSTR value;
  698. DWORD valueSize;
  699. DWORD valueType;
  700. DWORD status;
  701. //
  702. // Get the size of the value so we know how much to allocate.
  703. //
  704. valueSize = 0;
  705. status = ClusterRegQueryValue( hkeyClusterKey,
  706. pszValueName,
  707. &valueType,
  708. NULL,
  709. &valueSize );
  710. if ( (status != ERROR_SUCCESS) &&
  711. (status != ERROR_MORE_DATA) ) {
  712. SetLastError( status );
  713. return(NULL);
  714. }
  715. //
  716. // Add on the size of the null terminator.
  717. //
  718. valueSize += sizeof(UNICODE_NULL);
  719. //
  720. // Allocate a buffer to read the string into.
  721. //
  722. value = LocalAlloc( LMEM_FIXED, valueSize );
  723. if ( value == NULL ) {
  724. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  725. return(NULL);
  726. }
  727. //
  728. // Read the value from the cluster database.
  729. //
  730. status = ClusterRegQueryValue( hkeyClusterKey,
  731. pszValueName,
  732. &valueType,
  733. (LPBYTE)value,
  734. &valueSize );
  735. if ( status != ERROR_SUCCESS ) {
  736. LocalFree( value );
  737. value = NULL;
  738. } else if ( (valueType != REG_SZ) &&
  739. (valueType != REG_EXPAND_SZ) &&
  740. (valueType != REG_MULTI_SZ) ) {
  741. status = ERROR_INVALID_PARAMETER;
  742. LocalFree( value );
  743. value = NULL;
  744. }
  745. return(value);
  746. } // ResUtilGetSzValue
  747. PWSTR
  748. WINAPI
  749. ResUtilGetExpandSzValue(
  750. IN HKEY hkeyClusterKey,
  751. IN LPCWSTR pszValueName,
  752. IN BOOL bExpand
  753. )
  754. /*++
  755. Routine Description:
  756. Queries a REG_EXPAND_SZ value out of the cluster database and allocates
  757. the necessary storage for it, optionally expanding it.
  758. Arguments:
  759. hkeyClusterKey - Supplies the cluster key where the value is stored
  760. pszValueName - Supplies the name of the value.
  761. bExpand - TRUE = return the expanded string.
  762. Return Value:
  763. A pointer to a buffer containing the value if successful.
  764. NULL if unsuccessful. Call GetLastError() to get more details.
  765. --*/
  766. {
  767. PWSTR value;
  768. PWSTR pwszExpanded = NULL;
  769. DWORD valueSize;
  770. DWORD valueType;
  771. size_t cchExpanded;
  772. size_t cchExpandedReturned;
  773. DWORD sc;
  774. //
  775. // Get the size of the value so we know how much to allocate.
  776. //
  777. valueSize = 0;
  778. sc = ClusterRegQueryValue( hkeyClusterKey,
  779. pszValueName,
  780. &valueType,
  781. NULL,
  782. &valueSize );
  783. if ( (sc != ERROR_SUCCESS) &&
  784. (sc != ERROR_MORE_DATA) )
  785. {
  786. SetLastError( sc );
  787. return(NULL);
  788. }
  789. //
  790. // Add on the size of the null terminator.
  791. //
  792. valueSize += sizeof(UNICODE_NULL);
  793. //
  794. // Allocate a buffer to read the string into.
  795. //
  796. value = LocalAlloc( LMEM_FIXED, valueSize );
  797. if ( value == NULL )
  798. {
  799. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  800. return(NULL);
  801. }
  802. //
  803. // Read the value from the cluster database.
  804. //
  805. sc = ClusterRegQueryValue( hkeyClusterKey,
  806. pszValueName,
  807. &valueType,
  808. (LPBYTE)value,
  809. &valueSize );
  810. if ( sc != ERROR_SUCCESS )
  811. {
  812. LocalFree( value );
  813. value = NULL;
  814. }
  815. else if ( ( valueType != REG_EXPAND_SZ ) &&
  816. ( valueType != REG_SZ ) )
  817. {
  818. sc = ERROR_INVALID_PARAMETER;
  819. LocalFree( value );
  820. value = NULL;
  821. }
  822. else if ( bExpand )
  823. {
  824. //
  825. // Expand the environment variable strings in the
  826. // value that was just read.
  827. //
  828. cchExpanded = valueSize / sizeof( WCHAR );
  829. for (;;)
  830. {
  831. //
  832. // Allocate the buffer for the expansion string. This will
  833. // get double each time we are told it is too small.
  834. //
  835. pwszExpanded = LocalAlloc( LMEM_FIXED, cchExpanded * sizeof( WCHAR ) );
  836. if ( pwszExpanded == NULL )
  837. {
  838. sc = ERROR_NOT_ENOUGH_MEMORY;
  839. break;
  840. }
  841. else
  842. {
  843. //
  844. // Expand the environment variables in the value.
  845. // If the buffer isn't big enough, we will loop up to
  846. // the top of the loop and allocate a bigger buffer.
  847. //
  848. cchExpandedReturned = ExpandEnvironmentStringsW(
  849. value,
  850. pwszExpanded,
  851. (DWORD)cchExpanded );
  852. if ( cchExpandedReturned == 0 )
  853. {
  854. sc = GetLastError();
  855. break;
  856. }
  857. else if ( cchExpandedReturned > cchExpanded )
  858. {
  859. cchExpanded *= 2;
  860. LocalFree( pwszExpanded );
  861. pwszExpanded = NULL;
  862. continue;
  863. }
  864. else
  865. {
  866. sc = ERROR_SUCCESS;
  867. break;
  868. }
  869. }
  870. } // for: ever
  871. //
  872. // If any errors occurred, cleanup.
  873. // Otherwise, return expanded string.
  874. //
  875. if ( sc != ERROR_SUCCESS )
  876. {
  877. LocalFree( pwszExpanded );
  878. LocalFree( value );
  879. value = NULL;
  880. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  881. }
  882. else
  883. {
  884. LocalFree( value );
  885. value = pwszExpanded;
  886. }
  887. } // else: expand
  888. return(value);
  889. } // ResUtilGetExpandSzValue
  890. DWORD
  891. WINAPI
  892. ResUtilGetDwordValue(
  893. IN HKEY hkeyClusterKey,
  894. IN LPCWSTR pszValueName,
  895. OUT LPDWORD pdwOutValue,
  896. IN DWORD dwDefaultValue
  897. )
  898. /*++
  899. Routine Description:
  900. Queries a REG_DWORD value out of the cluster database.
  901. Arguments:
  902. hkeyClusterKey - Supplies the cluster key where the value is stored
  903. pszValueName - Supplies the name of the value.
  904. pdwOutValue - Supplies the address of a DWORD in which to return the value.
  905. dwDefaultValue - Value to return if the parameter is not found.
  906. Return Value:
  907. ERROR_SUCCESS - The value was read successfully.
  908. Win32 error code - The operation failed.
  909. --*/
  910. {
  911. DWORD value;
  912. DWORD valueSize;
  913. DWORD valueType;
  914. DWORD status;
  915. //
  916. // Initialize the output value.
  917. //
  918. *pdwOutValue = 0;
  919. //
  920. // Read the value from the cluster database.
  921. //
  922. valueSize = sizeof(DWORD);
  923. status = ClusterRegQueryValue( hkeyClusterKey,
  924. pszValueName,
  925. &valueType,
  926. (LPBYTE)&value,
  927. &valueSize );
  928. if ( status == ERROR_SUCCESS ) {
  929. if ( valueType != REG_DWORD ) {
  930. status = ERROR_INVALID_PARAMETER;
  931. } else {
  932. *pdwOutValue = value;
  933. }
  934. } else if ( status == ERROR_FILE_NOT_FOUND ) {
  935. *pdwOutValue = dwDefaultValue;
  936. status = ERROR_SUCCESS;
  937. }
  938. return(status);
  939. } // ResUtilGetDwordValue
  940. DWORD
  941. WINAPI
  942. ResUtilSetBinaryValue(
  943. IN HKEY hkeyClusterKey,
  944. IN LPCWSTR pszValueName,
  945. IN const LPBYTE pbNewValue,
  946. IN DWORD cbNewValueSize,
  947. IN OUT LPBYTE * ppbOutValue,
  948. IN OUT LPDWORD pcbOutValueSize
  949. )
  950. /*++
  951. Routine Description:
  952. Sets a REG_BINARY value in a pointer, deallocating a previous value
  953. if necessary, and sets the value in the cluster database.
  954. Arguments:
  955. hkeyClusterKey - Supplies the cluster key where the value is stored.
  956. pszValueName - Supplies the name of the value.
  957. pbNewValue - Supplies the new binary value.
  958. cbNewValueSize - Supplies the size of the new value.
  959. ppbOutValue - Supplies pointer to the binary pointer in which to set
  960. the value.
  961. pcbOutValueSize - Supplies a pointer to a size DWORD in which to set
  962. the size of the value.
  963. Return Value:
  964. ERROR_SUCCESS - The operation completed successfully.
  965. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  966. Win32 error code - The operation failed.
  967. --*/
  968. {
  969. DWORD status;
  970. LPBYTE allocedValue = NULL;
  971. if ( ppbOutValue != NULL )
  972. {
  973. //
  974. // Allocate memory for the new value.
  975. //
  976. allocedValue = LocalAlloc( LMEM_FIXED, cbNewValueSize );
  977. if ( allocedValue == NULL ) {
  978. return(ERROR_NOT_ENOUGH_MEMORY);
  979. }
  980. }
  981. //
  982. // Set the value in the cluster database.
  983. //
  984. // _ASSERTE( hkeyClusterKey != NULL );
  985. // _ASSERTE( pszValueName != NULL );
  986. status = ClusterRegSetValue( hkeyClusterKey,
  987. pszValueName,
  988. REG_BINARY,
  989. pbNewValue,
  990. cbNewValueSize );
  991. if ( status != ERROR_SUCCESS ) {
  992. LocalFree( allocedValue );
  993. return(status);
  994. }
  995. if ( ppbOutValue != NULL )
  996. {
  997. //
  998. // Copy the new value to the output buffer.
  999. //
  1000. CopyMemory( allocedValue, pbNewValue, cbNewValueSize );
  1001. // Set the new value in the output pointer.
  1002. if ( *ppbOutValue != NULL ) {
  1003. LocalFree( *ppbOutValue );
  1004. }
  1005. *ppbOutValue = allocedValue;
  1006. *pcbOutValueSize = cbNewValueSize;
  1007. }
  1008. return(ERROR_SUCCESS);
  1009. } // ResUtilSetBinaryValue
  1010. DWORD
  1011. WINAPI
  1012. ResUtilSetSzValue(
  1013. IN HKEY hkeyClusterKey,
  1014. IN LPCWSTR pszValueName,
  1015. IN LPCWSTR pszNewValue,
  1016. IN OUT LPWSTR * ppszOutValue
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. Sets a REG_SZ value in a pointer, deallocating a previous value
  1021. if necessary, and sets the value in the cluster database.
  1022. Arguments:
  1023. hkeyClusterKey - Supplies the cluster key where the value is stored.
  1024. pszValueName - Supplies the name of the value.
  1025. pszNewValue - Supplies the new string value.
  1026. ppszOutValue - Supplies pointer to the string pointer in which to set
  1027. the value.
  1028. Return Value:
  1029. ERROR_SUCCESS - The operation completed successfully.
  1030. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  1031. Win32 error code - The operation failed.
  1032. --*/
  1033. {
  1034. DWORD sc = ERROR_SUCCESS;
  1035. size_t cbData;
  1036. LPWSTR pwszAllocedValue = NULL;
  1037. HRESULT hr;
  1038. cbData = (wcslen( pszNewValue ) + 1) * sizeof(WCHAR);
  1039. if ( ppszOutValue != NULL )
  1040. {
  1041. //
  1042. // Allocate memory for the new value string.
  1043. //
  1044. pwszAllocedValue = LocalAlloc( LMEM_FIXED, cbData );
  1045. if ( pwszAllocedValue == NULL )
  1046. {
  1047. sc = ERROR_NOT_ENOUGH_MEMORY;
  1048. goto Cleanup;
  1049. }
  1050. }
  1051. //
  1052. // Set the value in the cluster database.
  1053. //
  1054. // _ASSERTE( hkeyClusterKey != NULL );
  1055. // _ASSERTE( pszValueName != NULL );
  1056. sc = ClusterRegSetValue( hkeyClusterKey,
  1057. pszValueName,
  1058. REG_SZ,
  1059. (CONST BYTE*)pszNewValue,
  1060. (DWORD)cbData );
  1061. if ( sc != ERROR_SUCCESS )
  1062. {
  1063. goto Cleanup;
  1064. }
  1065. if ( ppszOutValue != NULL )
  1066. {
  1067. //
  1068. // Copy the new value to the output buffer.
  1069. //
  1070. hr = StringCbCopyW( pwszAllocedValue, cbData, pszNewValue );
  1071. if ( FAILED( hr ) )
  1072. {
  1073. sc = HRESULT_CODE( hr );
  1074. goto Cleanup;
  1075. }
  1076. // Set the new value in the output string pointer.
  1077. if ( *ppszOutValue != NULL )
  1078. {
  1079. LocalFree( *ppszOutValue );
  1080. }
  1081. *ppszOutValue = pwszAllocedValue;
  1082. pwszAllocedValue = NULL;
  1083. }
  1084. sc = ERROR_SUCCESS;
  1085. Cleanup:
  1086. LocalFree( pwszAllocedValue );
  1087. return sc;
  1088. } // ResUtilSetSzValue
  1089. DWORD
  1090. WINAPI
  1091. ResUtilSetExpandSzValue(
  1092. IN HKEY hkeyClusterKey,
  1093. IN LPCWSTR pszValueName,
  1094. IN LPCWSTR pszNewValue,
  1095. IN OUT LPWSTR * ppszOutValue
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. Sets a REG_EXPAND_SZ value in a pointer, deallocating a previous value
  1100. if necessary, and sets the value in the cluster database.
  1101. Arguments:
  1102. hkeyClusterKey - Supplies the cluster key where the value is stored.
  1103. pszValueName - Supplies the name of the value.
  1104. pszNewValue - Supplies the new string value.
  1105. ppszOutValue - Supplies pointer to the string pointer in which to set
  1106. the value.
  1107. Return Value:
  1108. ERROR_SUCCESS - The operation completed successfully.
  1109. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  1110. Win32 error code - The operation failed.
  1111. --*/
  1112. {
  1113. DWORD sc;
  1114. DWORD dataSize;
  1115. PWSTR allocedValue = NULL;
  1116. HRESULT hr;
  1117. dataSize = ((DWORD) wcslen( pszNewValue ) + 1) * sizeof(WCHAR);
  1118. if ( ppszOutValue != NULL ) {
  1119. //
  1120. // Allocate memory for the new value string.
  1121. //
  1122. allocedValue = LocalAlloc( LMEM_FIXED, dataSize );
  1123. if ( allocedValue == NULL )
  1124. {
  1125. sc = ERROR_NOT_ENOUGH_MEMORY;
  1126. goto Cleanup;
  1127. }
  1128. }
  1129. //
  1130. // Set the value in the cluster database.
  1131. //
  1132. // _ASSERTE( hkeyClusterKey != NULL );
  1133. // _ASSERTE( pszValueName != NULL );
  1134. sc = ClusterRegSetValue( hkeyClusterKey,
  1135. pszValueName,
  1136. REG_EXPAND_SZ,
  1137. (CONST BYTE*)pszNewValue,
  1138. dataSize );
  1139. if ( sc != ERROR_SUCCESS )
  1140. {
  1141. goto Cleanup;
  1142. }
  1143. if ( ppszOutValue != NULL )
  1144. {
  1145. //
  1146. // Copy the new value to the output buffer.
  1147. //
  1148. hr = StringCbCopyW( allocedValue, dataSize, pszNewValue );
  1149. if ( FAILED( hr ) )
  1150. {
  1151. sc = HRESULT_CODE( hr );
  1152. goto Cleanup;
  1153. }
  1154. // Set the new value in the output string pointer.
  1155. if ( *ppszOutValue != NULL )
  1156. {
  1157. LocalFree( *ppszOutValue );
  1158. }
  1159. *ppszOutValue = allocedValue;
  1160. allocedValue = NULL;
  1161. }
  1162. sc = ERROR_SUCCESS;
  1163. Cleanup:
  1164. LocalFree( allocedValue );
  1165. return sc;
  1166. } // ResUtilSetSzValue
  1167. DWORD
  1168. WINAPI
  1169. ResUtilSetMultiSzValue(
  1170. IN HKEY hkeyClusterKey,
  1171. IN LPCWSTR pszValueName,
  1172. IN LPCWSTR pszNewValue,
  1173. IN DWORD cbNewValueSize,
  1174. IN OUT LPWSTR * ppszOutValue,
  1175. IN OUT LPDWORD pcbOutValueSize
  1176. )
  1177. /*++
  1178. Routine Description:
  1179. Sets a REG_MULTI_SZ value in a pointer, deallocating a previous value
  1180. if necessary, and sets the value in the cluster database.
  1181. Arguments:
  1182. hkeyClusterKey - Supplies the cluster key where the ValueName is stored.
  1183. pszValueName - Supplies the name of the value.
  1184. pszNewValue - Supplies the new MULTI_SZ value.
  1185. cbNewValueSize - Supplies the size of the new value.
  1186. ppszOutValue - Supplies a pointer to the string pointer in which to set
  1187. the value.
  1188. pcbOutValueSize - Supplies a pointer to a size DWORD in which to set
  1189. the size of the value.
  1190. Return Value:
  1191. ERROR_SUCCESS - The operation completed successfully.
  1192. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  1193. Win32 error code - The operation failed.
  1194. --*/
  1195. {
  1196. DWORD status;
  1197. LPWSTR allocedValue = NULL;
  1198. if ( ppszOutValue != NULL )
  1199. {
  1200. //
  1201. // Allocate memory for the new value.
  1202. //
  1203. allocedValue = LocalAlloc( LMEM_FIXED, cbNewValueSize );
  1204. if ( allocedValue == NULL ) {
  1205. return(ERROR_NOT_ENOUGH_MEMORY);
  1206. }
  1207. }
  1208. //
  1209. // Set the value in the cluster database.
  1210. //
  1211. // _ASSERTE( hkeyClusterKey != NULL );
  1212. // _ASSERTE( pszValueName != NULL );
  1213. status = ClusterRegSetValue( hkeyClusterKey,
  1214. pszValueName,
  1215. REG_MULTI_SZ,
  1216. (CONST BYTE*)pszNewValue,
  1217. cbNewValueSize );
  1218. if ( status != ERROR_SUCCESS ) {
  1219. LocalFree(allocedValue);
  1220. return(status);
  1221. }
  1222. if ( ppszOutValue != NULL )
  1223. {
  1224. //
  1225. // Copy the new value to the output buffer.
  1226. //
  1227. CopyMemory( allocedValue, pszNewValue, cbNewValueSize );
  1228. // Set the new value in the output pointer.
  1229. if ( *ppszOutValue != NULL ) {
  1230. LocalFree( *ppszOutValue );
  1231. }
  1232. *ppszOutValue = allocedValue;
  1233. *pcbOutValueSize = cbNewValueSize;
  1234. }
  1235. return(ERROR_SUCCESS);
  1236. } // ResUtilSetMultiSzValue
  1237. DWORD
  1238. WINAPI
  1239. ResUtilSetDwordValue(
  1240. IN HKEY hkeyClusterKey,
  1241. IN LPCWSTR pszValueName,
  1242. IN DWORD dwNewValue,
  1243. IN OUT LPDWORD pdwOutValue
  1244. )
  1245. /*++
  1246. Routine Description:
  1247. Sets a REG_DWORD value in a pointer and sets the value in the
  1248. cluster database.
  1249. Arguments:
  1250. hkeyClusterKey - Supplies the cluster key where the property is stored.
  1251. pszValueName - Supplies the name of the value.
  1252. dwNewValue - Supplies the new DWORD value.
  1253. pdwOutValue - Supplies pointer to the DWORD pointer in which to set
  1254. the value.
  1255. Return Value:
  1256. ERROR_SUCCESS - The operation completed successfully.
  1257. Win32 error code - The operation failed.
  1258. --*/
  1259. {
  1260. DWORD status;
  1261. //
  1262. // Set the value in the cluster database.
  1263. //
  1264. // _ASSERTE( hkeyClusterKey != NULL );
  1265. // _ASSERTE( pszValueName != NULL );
  1266. status = ClusterRegSetValue( hkeyClusterKey,
  1267. pszValueName,
  1268. REG_DWORD,
  1269. (CONST BYTE*)&dwNewValue,
  1270. sizeof(DWORD) );
  1271. if ( status != ERROR_SUCCESS ) {
  1272. return(status);
  1273. }
  1274. if ( pdwOutValue != NULL )
  1275. {
  1276. //
  1277. // Copy the new value to the output buffer.
  1278. //
  1279. *pdwOutValue = dwNewValue;
  1280. }
  1281. return(ERROR_SUCCESS);
  1282. } // ResUtilSetDwordValue
  1283. DWORD
  1284. WINAPI
  1285. ResUtilGetBinaryProperty(
  1286. OUT LPBYTE * ppbOutValue,
  1287. OUT LPDWORD pcbOutValueSize,
  1288. IN const PCLUSPROP_BINARY pValueStruct,
  1289. IN const LPBYTE pbOldValue,
  1290. IN DWORD cbOldValueSize,
  1291. OUT LPBYTE * ppPropertyList,
  1292. OUT LPDWORD pcbPropertyListSize
  1293. )
  1294. /*++
  1295. Routine Description:
  1296. Gets a binary property from a property list and advances the pointers.
  1297. Arguments:
  1298. ppbOutValue - Supplies the address of a pointer in which to return a
  1299. pointer to the binary value in the property list.
  1300. pcbOutValueSize - Supplies the address of the output value size.
  1301. pValueStruct - Supplies the binary value from the property list.
  1302. pbOldValue - Supplies the previous value for this property.
  1303. cbOldValueSize - Supplies the previous value's size.
  1304. ppPropertyList - Supplies the address of the pointer to the property list
  1305. buffer which will be advanced to the beginning of the next property.
  1306. pcbPropertyListSize - Supplies a pointer to the buffer size which will be
  1307. decremented to account for this property.
  1308. Return Value:
  1309. ERROR_SUCCESS - The operation completed successfully.
  1310. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1311. Win32 error code - The operation failed.
  1312. --*/
  1313. {
  1314. BOOL propChanged = FALSE;
  1315. DWORD arrayIndex;
  1316. DWORD dataSize;
  1317. //
  1318. // Make sure the buffer is big enough and
  1319. // the value is formatted correctly.
  1320. //
  1321. dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
  1322. if ( (*pcbPropertyListSize < dataSize) ||
  1323. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_BINARY) ) {
  1324. return(ERROR_INVALID_PARAMETER);
  1325. }
  1326. //
  1327. // If the value changed, point to the new value.
  1328. //
  1329. if ( (pbOldValue == NULL) ||
  1330. (cbOldValueSize != pValueStruct->cbLength) ) {
  1331. propChanged = TRUE;
  1332. } else {
  1333. for ( arrayIndex = 0 ; arrayIndex < cbOldValueSize ; arrayIndex++ ) {
  1334. if ( pValueStruct->rgb[arrayIndex] != pbOldValue[arrayIndex] ) {
  1335. propChanged = TRUE;
  1336. break;
  1337. }
  1338. }
  1339. }
  1340. if ( propChanged ) {
  1341. *ppbOutValue = pValueStruct->rgb;
  1342. *pcbOutValueSize = pValueStruct->cbLength;
  1343. }
  1344. //
  1345. // Decrement remaining buffer size and move to the next property.
  1346. //
  1347. *pcbPropertyListSize -= dataSize;
  1348. *ppPropertyList += dataSize;
  1349. return(ERROR_SUCCESS);
  1350. } // ResUtilGetBinaryProperty
  1351. DWORD
  1352. WINAPI
  1353. ResUtilGetSzProperty(
  1354. OUT LPWSTR * ppszOutValue,
  1355. IN const PCLUSPROP_SZ pValueStruct,
  1356. IN LPCWSTR pszOldValue,
  1357. OUT LPBYTE * ppPropertyList,
  1358. OUT LPDWORD pcbPropertyListSize
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. Gets a string property from a property list and advances the pointers.
  1363. Arguments:
  1364. ppszOutValue - Supplies the address of a pointer in which to return a
  1365. pointer to the string in the property list.
  1366. pValueStruct - Supplies the string value from the property list.
  1367. pszOldValue - Supplies the previous value for this property.
  1368. ppPropertyList - Supplies the address of the pointer to the property list
  1369. buffer which will be advanced to the beginning of the next property.
  1370. pcbPropertyListSize - Supplies a pointer to the buffer size which will be
  1371. decremented to account for this property.
  1372. Return Value:
  1373. ERROR_SUCCESS - The operation completed successfully.
  1374. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1375. Win32 error code - The operation failed.
  1376. --*/
  1377. {
  1378. DWORD dataSize;
  1379. DWORD sc = ERROR_SUCCESS;
  1380. //
  1381. // Make sure the buffer is big enough and
  1382. // the value is formatted correctly.
  1383. //
  1384. dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
  1385. if ( (*pcbPropertyListSize < dataSize) ||
  1386. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_SZ) ||
  1387. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_EXPAND_SZ) )
  1388. {
  1389. sc = ERROR_INVALID_PARAMETER;
  1390. goto Cleanup;
  1391. }
  1392. //
  1393. // If the value changed, point to the new value.
  1394. // Do this even if only the case of the value changed.
  1395. //
  1396. if ( (pszOldValue == NULL) ||
  1397. (wcsncmp( pValueStruct->sz, pszOldValue, pValueStruct->cbLength / sizeof( WCHAR ) ) != 0)
  1398. )
  1399. {
  1400. *ppszOutValue = pValueStruct->sz;
  1401. }
  1402. //
  1403. // Decrement remaining buffer size and move to the next property.
  1404. //
  1405. *pcbPropertyListSize -= dataSize;
  1406. *ppPropertyList += dataSize;
  1407. Cleanup:
  1408. return sc;
  1409. } // ResUtilGetSzProperty
  1410. DWORD
  1411. WINAPI
  1412. ResUtilGetMultiSzProperty(
  1413. OUT LPWSTR * ppszOutValue,
  1414. OUT LPDWORD pcbOutValueSize,
  1415. IN const PCLUSPROP_SZ pValueStruct,
  1416. IN LPCWSTR pszOldValue,
  1417. IN DWORD cbOldValueSize,
  1418. OUT LPBYTE * ppPropertyList,
  1419. OUT LPDWORD pcbPropertyListSize
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. Gets a binary property from a property list and advances the pointers.
  1424. Arguments:
  1425. ppszOutValue - Supplies the address of a pointer in which to return a
  1426. pointer to the binary value in the property list.
  1427. pcbOutValueSize - Supplies the address of the output value size.
  1428. pValueStruct - Supplies the string value from the property list.
  1429. pszOldValue - Supplies the previous value for this property.
  1430. cbOldValueSize - Supplies the previous value's size.
  1431. ppPropertyList - Supplies the address of the pointer to the property list
  1432. buffer which will be advanced to the beginning of the next property.
  1433. pcbPropertyListSize - Supplies a pointer to the buffer size which will be
  1434. decremented to account for this property.
  1435. Return Value:
  1436. ERROR_SUCCESS - The operation completed successfully.
  1437. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1438. Win32 error code - The operation failed.
  1439. --*/
  1440. {
  1441. BOOL propChanged = FALSE;
  1442. DWORD dataSize;
  1443. //
  1444. // Make sure the buffer is big enough and
  1445. // the value is formatted correctly.
  1446. //
  1447. dataSize = sizeof(*pValueStruct) + ALIGN_CLUSPROP( pValueStruct->cbLength );
  1448. if ( (*pcbPropertyListSize < dataSize) ||
  1449. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_MULTI_SZ) ) {
  1450. return(ERROR_INVALID_PARAMETER);
  1451. }
  1452. //
  1453. // If the value changed, point to the new value.
  1454. //
  1455. if ( (pszOldValue == NULL) ||
  1456. (cbOldValueSize != pValueStruct->cbLength) ) {
  1457. propChanged = TRUE;
  1458. } else if ( memcmp( pValueStruct->sz, pszOldValue, cbOldValueSize ) != 0 ) {
  1459. propChanged = TRUE;
  1460. }
  1461. if ( propChanged ) {
  1462. *ppszOutValue = pValueStruct->sz;
  1463. *pcbOutValueSize = pValueStruct->cbLength;
  1464. }
  1465. //
  1466. // Decrement remaining buffer size and move to the next property.
  1467. //
  1468. *pcbPropertyListSize -= dataSize;
  1469. *ppPropertyList += dataSize;
  1470. return(ERROR_SUCCESS);
  1471. } // ResUtilGetMultiSzProperty
  1472. DWORD
  1473. WINAPI
  1474. ResUtilGetDwordProperty(
  1475. OUT LPDWORD pdwOutValue,
  1476. IN const PCLUSPROP_DWORD pValueStruct,
  1477. IN DWORD dwOldValue,
  1478. IN DWORD dwMinimum,
  1479. IN DWORD dwMaximum,
  1480. OUT LPBYTE * ppPropertyList,
  1481. OUT LPDWORD pcbPropertyListSize
  1482. )
  1483. /*++
  1484. Routine Description:
  1485. Gets a DWORD property from a property list and advances the pointers.
  1486. Arguments:
  1487. pdwOutValue - Supplies the address of a pointer in which to return a
  1488. pointer to the string in the property list.
  1489. pValueStruct - Supplies the DWORD value from the property list.
  1490. dwOldValue - Supplies the previous value for this property.
  1491. dwMinimum - Minimum value the value can have. If both Minimum and Maximum
  1492. are 0, no range check will be done.
  1493. dwMaximum - Maximum value the value can have.
  1494. ppPropertyList - Supplies the address of the pointer to the property list
  1495. buffer which will be advanced to the beginning of the next property.
  1496. pcbPropertyListSize - Supplies a pointer to the buffer size which will be
  1497. decremented to account for this property.
  1498. Return Value:
  1499. ERROR_SUCCESS - The operation completed successfully.
  1500. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1501. Win32 error code - The operation failed.
  1502. --*/
  1503. {
  1504. size_t cbData;
  1505. DWORD sc = ERROR_SUCCESS;
  1506. UNREFERENCED_PARAMETER( dwOldValue );
  1507. //
  1508. // Make sure the buffer is big enough and
  1509. // the value is formatted correctly.
  1510. //
  1511. cbData = sizeof(*pValueStruct);
  1512. if ( (*pcbPropertyListSize < cbData) ||
  1513. (pValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_DWORD) ||
  1514. (pValueStruct->cbLength != sizeof(DWORD)) )
  1515. {
  1516. sc = ERROR_INVALID_PARAMETER;
  1517. goto Cleanup;
  1518. }
  1519. //
  1520. // Make sure the value is in range.
  1521. //
  1522. if ( (dwMinimum != 0) && (dwMaximum != 0) )
  1523. {
  1524. if ( (pValueStruct->dw < dwMinimum) ||
  1525. (pValueStruct->dw > dwMaximum) )
  1526. {
  1527. sc = ERROR_INVALID_PARAMETER;
  1528. goto Cleanup;
  1529. }
  1530. }
  1531. //
  1532. // Set to the new value.
  1533. //
  1534. *pdwOutValue = pValueStruct->dw;
  1535. //
  1536. // Decrement remaining buffer size and move to the next property.
  1537. //
  1538. *pcbPropertyListSize -= (DWORD) cbData;
  1539. *ppPropertyList += cbData;
  1540. Cleanup:
  1541. return sc;
  1542. } // ResUtilGetDwordProperty
  1543. static DWORD
  1544. ScBuildNetNameEnvironment(
  1545. IN LPWSTR pszNetworkName,
  1546. IN DWORD cchNetworkNameBufferSize,
  1547. IN OUT LPVOID * ppvEnvironment OPTIONAL
  1548. )
  1549. {
  1550. UNICODE_STRING usValueName;
  1551. UNICODE_STRING usValue;
  1552. DWORD sc = ERROR_SUCCESS;
  1553. NTSTATUS ntStatus;
  1554. DWORD cchDomain;
  1555. DWORD cchNetworkName = (DWORD)wcslen( pszNetworkName );
  1556. PVOID pvEnvBlock = NULL;
  1557. //
  1558. // validate parameters
  1559. //
  1560. if ( cchNetworkName == 0 ||
  1561. cchNetworkNameBufferSize == 0 ||
  1562. pszNetworkName == NULL ||
  1563. *pszNetworkName == UNICODE_NULL
  1564. )
  1565. {
  1566. return ERROR_INVALID_PARAMETER;
  1567. }
  1568. //
  1569. // if no env. block was passed in, create one since the RTL routines will
  1570. // modify the current process' environment if NULL is passed into
  1571. // RtlSetEnvironmentVariable
  1572. //
  1573. if ( *ppvEnvironment == NULL )
  1574. {
  1575. ntStatus = RtlCreateEnvironment( FALSE, // don't clone current environment
  1576. &pvEnvBlock );
  1577. if ( ! NT_SUCCESS( ntStatus ))
  1578. {
  1579. sc = RtlNtStatusToDosError( ntStatus );
  1580. goto Error;
  1581. }
  1582. }
  1583. else
  1584. {
  1585. pvEnvBlock = *ppvEnvironment;
  1586. }
  1587. //
  1588. // Add the virtual netname to the cloned environment
  1589. //
  1590. RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_NAME_" );
  1591. RtlInitUnicodeString( &usValue, pszNetworkName );
  1592. ntStatus = RtlSetEnvironmentVariable(
  1593. &pvEnvBlock,
  1594. &usValueName,
  1595. &usValue
  1596. );
  1597. if ( ! NT_SUCCESS( ntStatus ) )
  1598. {
  1599. sc = RtlNtStatusToDosError( ntStatus );
  1600. goto Error;
  1601. }
  1602. //
  1603. // add the netname as the DNS hostname
  1604. //
  1605. RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_HOSTNAME_" );
  1606. ntStatus = RtlSetEnvironmentVariable(
  1607. &pvEnvBlock,
  1608. &usValueName,
  1609. &usValue
  1610. );
  1611. if ( ! NT_SUCCESS( ntStatus ) )
  1612. {
  1613. sc = RtlNtStatusToDosError( ntStatus );
  1614. goto Error;
  1615. }
  1616. //
  1617. // Change the COMPUTERNAME environment variable to match.
  1618. //
  1619. RtlInitUnicodeString( &usValueName, L"COMPUTERNAME" );
  1620. ntStatus = RtlSetEnvironmentVariable(
  1621. &pvEnvBlock,
  1622. &usValueName,
  1623. &usValue
  1624. );
  1625. if ( ! NT_SUCCESS( ntStatus ) )
  1626. {
  1627. sc = RtlNtStatusToDosError( ntStatus );
  1628. goto Error;
  1629. }
  1630. //
  1631. // Now generate the string for the FQDN
  1632. //
  1633. RtlInitUnicodeString( &usValueName, L"_CLUSTER_NETWORK_FQDN_" );
  1634. pszNetworkName[ cchNetworkName ] = L'.';
  1635. cchDomain = cchNetworkNameBufferSize - cchNetworkName - 1;
  1636. if ( GetComputerNameExW(
  1637. ComputerNameDnsDomain,
  1638. &pszNetworkName[ cchNetworkName + 1 ],
  1639. &cchDomain )
  1640. )
  1641. {
  1642. if ( cchDomain == 0 )
  1643. {
  1644. pszNetworkName[ cchNetworkName ] = L'\0';
  1645. }
  1646. }
  1647. else
  1648. {
  1649. //
  1650. // Error from trying to get the DNS Domain name.
  1651. // Just don't set the DnsDomain name!
  1652. //
  1653. goto Error;
  1654. }
  1655. RtlInitUnicodeString( &usValue, pszNetworkName );
  1656. //
  1657. // Add in the FQDN name
  1658. //
  1659. ntStatus = RtlSetEnvironmentVariable(
  1660. &pvEnvBlock,
  1661. &usValueName,
  1662. &usValue
  1663. );
  1664. if ( ! NT_SUCCESS( ntStatus ) )
  1665. {
  1666. sc = RtlNtStatusToDosError( ntStatus );
  1667. goto Error;
  1668. }
  1669. Exit:
  1670. *ppvEnvironment = pvEnvBlock;
  1671. return sc;
  1672. Error:
  1673. if ( pvEnvBlock != NULL )
  1674. {
  1675. RtlDestroyEnvironment( pvEnvBlock );
  1676. pvEnvBlock = NULL;
  1677. }
  1678. goto Exit;
  1679. } // ScBuildNetNameEnvironment
  1680. static DWORD
  1681. ScGetNameFromNetnameResource(
  1682. HRESOURCE hNetNameResource,
  1683. LPWSTR * ppszNetworkName
  1684. )
  1685. {
  1686. DWORD sc = ERROR_SUCCESS;
  1687. BOOL fSuccess = FALSE;
  1688. LPWSTR pszNetworkName = NULL;
  1689. DWORD cchNetworkName = 0;
  1690. DWORD cchAllocSize = 0;
  1691. //
  1692. // First find out the network name
  1693. //
  1694. cchNetworkName = DNS_MAX_NAME_BUFFER_LENGTH;
  1695. cchAllocSize = cchNetworkName;
  1696. pszNetworkName = LocalAlloc( LMEM_FIXED, cchAllocSize * sizeof( pszNetworkName[ 0 ] ) );
  1697. if ( pszNetworkName == NULL )
  1698. {
  1699. sc = ERROR_NOT_ENOUGH_MEMORY;
  1700. goto Cleanup;
  1701. }
  1702. fSuccess = GetClusterResourceNetworkName(
  1703. hNetNameResource
  1704. , pszNetworkName
  1705. , &cchNetworkName
  1706. );
  1707. if ( ! fSuccess )
  1708. {
  1709. sc = GetLastError();
  1710. if ( sc == ERROR_MORE_DATA )
  1711. {
  1712. LocalFree( pszNetworkName );
  1713. cchNetworkName++;
  1714. cchNetworkName *= 2;
  1715. cchAllocSize = cchNetworkName;
  1716. pszNetworkName = LocalAlloc( LMEM_FIXED, cchAllocSize * sizeof( pszNetworkName[ 0 ] ) );
  1717. if ( pszNetworkName == NULL )
  1718. {
  1719. sc = ERROR_NOT_ENOUGH_MEMORY;
  1720. goto Cleanup;
  1721. } // if:
  1722. fSuccess = GetClusterResourceNetworkName(
  1723. hNetNameResource
  1724. , pszNetworkName
  1725. , &cchNetworkName
  1726. );
  1727. }
  1728. if ( ! fSuccess )
  1729. {
  1730. sc = GetLastError();
  1731. goto Cleanup;
  1732. }
  1733. } // if: !fSuccess
  1734. Cleanup:
  1735. if ( sc != ERROR_SUCCESS )
  1736. {
  1737. LocalFree( pszNetworkName );
  1738. pszNetworkName = NULL;
  1739. SetLastError( sc );
  1740. }
  1741. *ppszNetworkName = pszNetworkName;
  1742. return cchAllocSize;
  1743. } // ScGetNameFromNetnameResource
  1744. LPVOID
  1745. WINAPI
  1746. ResUtilGetEnvironmentWithNetName(
  1747. IN HRESOURCE hResource
  1748. )
  1749. /*++
  1750. Routine Description:
  1751. Creates an environment block based on the current thread or process
  1752. token's environment block, but with the addition of a
  1753. _CLUSTER_NETWORK_NAME=xxx environment value. xxx in this case represents
  1754. the network name of the supplied resource. This environment block is
  1755. suitable for passing to CreateProcess to create an environment that will
  1756. cause GetComputerName to lie to the application.
  1757. THIS API SHOULDN'T BE USED TO CREATE A SERVICE'S ENVIRONMENT unless the
  1758. service runs in the same user account context as that of the caller. The
  1759. service will end up with the caller's environment instead of the account
  1760. associated with the service. Use ResUtilSetResourceServiceEnvironment for
  1761. this purpose.
  1762. _CLUSTER_NETWORK_FQDN_ will be set to the fully qualified DNS name using
  1763. the primary DNS suffix for this node.
  1764. Arguments:
  1765. hResource - Supplies the resource
  1766. Return Value:
  1767. pointer to the environment block if successful.
  1768. NULL otherwise
  1769. --*/
  1770. {
  1771. PVOID pvEnvironment = NULL;
  1772. DWORD sc = ERROR_SUCCESS;
  1773. NTSTATUS ntStatus;
  1774. BOOL fSuccess;
  1775. LPWSTR pszNetworkName = NULL;
  1776. DWORD cchNetworkNameBufferSize;
  1777. HANDLE hToken = NULL;
  1778. //
  1779. // get the Name property of the netname represented by hResource
  1780. //
  1781. cchNetworkNameBufferSize = ScGetNameFromNetnameResource( hResource, &pszNetworkName );
  1782. if ( pszNetworkName == NULL )
  1783. {
  1784. sc = GetLastError();
  1785. goto Cleanup;
  1786. }
  1787. //
  1788. // see if the calling thread has a token. If so, we'll use that token's
  1789. // identity for getting the environment. If not, get the current process
  1790. // token. If that fails, we revert to using just the system environment
  1791. // area.
  1792. //
  1793. fSuccess = OpenThreadToken(GetCurrentThread(),
  1794. TOKEN_IMPERSONATE | TOKEN_QUERY,
  1795. TRUE,
  1796. &hToken);
  1797. if ( !fSuccess )
  1798. {
  1799. OpenProcessToken(GetCurrentProcess(),
  1800. TOKEN_IMPERSONATE | TOKEN_QUERY,
  1801. &hToken );
  1802. }
  1803. //
  1804. // Clone the current environment, picking up any changes that might have
  1805. // been made after resmon started
  1806. //
  1807. fSuccess = CreateEnvironmentBlock( &pvEnvironment, hToken, FALSE );
  1808. if ( ! fSuccess )
  1809. {
  1810. sc = GetLastError();
  1811. goto Cleanup;
  1812. }
  1813. ntStatus = ScBuildNetNameEnvironment( pszNetworkName, cchNetworkNameBufferSize, &pvEnvironment );
  1814. if ( ! NT_SUCCESS( ntStatus ) )
  1815. {
  1816. sc = RtlNtStatusToDosError( ntStatus );
  1817. goto Error;
  1818. }
  1819. Cleanup:
  1820. CloseHandle( hToken );
  1821. LocalFree( pszNetworkName );
  1822. SetLastError( sc );
  1823. return pvEnvironment;
  1824. Error:
  1825. if ( pvEnvironment != NULL )
  1826. {
  1827. RtlDestroyEnvironment( pvEnvironment );
  1828. pvEnvironment = NULL;
  1829. }
  1830. goto Cleanup;
  1831. } // ResUtilGetEnvironmentWithNetName
  1832. //***************************************************************************
  1833. //
  1834. // Worker thread routines
  1835. //
  1836. //***************************************************************************
  1837. DWORD
  1838. WINAPI
  1839. ClusWorkerStart(
  1840. IN PWORK_CONTEXT pContext
  1841. )
  1842. /*++
  1843. Routine Description:
  1844. Wrapper routine for cluster resource worker startup
  1845. Arguments:
  1846. Context - Supplies the context block. This will be freed.
  1847. Return Value:
  1848. ERROR_SUCCESS
  1849. --*/
  1850. {
  1851. DWORD Status;
  1852. WORK_CONTEXT Context;
  1853. //
  1854. // Capture our parameters and free the work context.
  1855. //
  1856. Context = *pContext;
  1857. LocalFree(pContext);
  1858. //
  1859. // Call the worker routine
  1860. //
  1861. Status = (Context.lpStartRoutine)(Context.Worker, Context.lpParameter);
  1862. //
  1863. // Synchronize and clean up properly.
  1864. //
  1865. EnterCriticalSection(&ResUtilWorkerLock);
  1866. if (!Context.Worker->Terminate) {
  1867. CloseHandle(Context.Worker->hThread);
  1868. Context.Worker->hThread = NULL;
  1869. }
  1870. Context.Worker->Terminate = TRUE;
  1871. LeaveCriticalSection(&ResUtilWorkerLock);
  1872. return(Status);
  1873. } // ClusWorkerStart
  1874. DWORD
  1875. WINAPI
  1876. ClusWorkerCreate(
  1877. OUT PCLUS_WORKER lpWorker,
  1878. IN PWORKER_START_ROUTINE lpStartAddress,
  1879. IN PVOID lpParameter
  1880. )
  1881. /*++
  1882. Routine Description:
  1883. Common wrapper for resource DLL worker threads. Provides
  1884. "clean" terminate semantics
  1885. Arguments:
  1886. lpWorker - Returns an initialized worker structure
  1887. lpStartAddress - Supplies the worker thread routine
  1888. lpParameter - Supplies the parameter to be passed to the
  1889. worker thread routine
  1890. Return Value:
  1891. ERROR_SUCCESS if successful
  1892. Win32 error code otherwise
  1893. --*/
  1894. {
  1895. PWORK_CONTEXT Context;
  1896. DWORD ThreadId;
  1897. DWORD Status;
  1898. Context = LocalAlloc(LMEM_FIXED, sizeof(WORK_CONTEXT));
  1899. if (Context == NULL) {
  1900. return(ERROR_NOT_ENOUGH_MEMORY);
  1901. }
  1902. Context->Worker = lpWorker;
  1903. Context->lpParameter = lpParameter;
  1904. Context->lpStartRoutine = lpStartAddress;
  1905. lpWorker->Terminate = FALSE;
  1906. lpWorker->hThread = CreateThread(NULL,
  1907. 0,
  1908. ClusWorkerStart,
  1909. Context,
  1910. 0,
  1911. &ThreadId);
  1912. if (lpWorker->hThread == NULL) {
  1913. Status = GetLastError();
  1914. LocalFree(Context);
  1915. return(Status);
  1916. }
  1917. return(ERROR_SUCCESS);
  1918. } // ClusWorkerCreate
  1919. BOOL
  1920. WINAPI
  1921. ClusWorkerCheckTerminate(
  1922. IN PCLUS_WORKER lpWorker
  1923. )
  1924. /*++
  1925. Routine Description:
  1926. Checks to see if the specified Worker thread should exit ASAP.
  1927. Arguments:
  1928. lpWorker - Supplies the worker
  1929. Return Value:
  1930. TRUE if the thread should exit.
  1931. FALSE otherwise
  1932. --*/
  1933. {
  1934. return(lpWorker->Terminate);
  1935. } // ClusWorkerCheckTerminate
  1936. VOID
  1937. WINAPI
  1938. ClusWorkerTerminate(
  1939. IN PCLUS_WORKER lpWorker
  1940. )
  1941. /*++
  1942. Routine Description:
  1943. Checks to see if the specified Worker thread should exit ASAP.
  1944. Arguments:
  1945. lpWorker - Supplies the worker
  1946. Return Value:
  1947. None.
  1948. --*/
  1949. {
  1950. //
  1951. // N.B. There is a race condition here if multiple threads
  1952. // call this routine on the same worker. The first one
  1953. // through will set Terminate. The second one will see
  1954. // that Terminate is set and return immediately without
  1955. // waiting for the Worker to exit. Not really any nice
  1956. // way to fix this without adding another synchronization
  1957. // object.
  1958. //
  1959. if ((lpWorker->hThread == NULL) ||
  1960. (lpWorker->Terminate)) {
  1961. return;
  1962. }
  1963. EnterCriticalSection(&ResUtilWorkerLock);
  1964. if (!lpWorker->Terminate) {
  1965. lpWorker->Terminate = TRUE;
  1966. LeaveCriticalSection(&ResUtilWorkerLock);
  1967. WaitForSingleObject(lpWorker->hThread, INFINITE);
  1968. CloseHandle(lpWorker->hThread);
  1969. lpWorker->hThread = NULL;
  1970. } else {
  1971. LeaveCriticalSection(&ResUtilWorkerLock);
  1972. }
  1973. return;
  1974. } // ClusWorkerTerminate
  1975. DWORD
  1976. WINAPI
  1977. ResUtilCreateDirectoryTree(
  1978. IN LPCWSTR pszPath
  1979. )
  1980. /*++
  1981. Routine Description:
  1982. Creates all the directories in the specified path.
  1983. ERROR_ALREADY_EXISTS will never be returned by this routine.
  1984. Arguments:
  1985. pszPath - String containing a path.
  1986. Return Value:
  1987. ERROR_SUCCESS - The operation completed successfully
  1988. Win32 error code - The operation failed.
  1989. --*/
  1990. {
  1991. return( ClRtlCreateDirectory( pszPath ) );
  1992. } // ResUtilCreateDirectoryTree
  1993. BOOL
  1994. WINAPI
  1995. ResUtilIsPathValid(
  1996. IN LPCWSTR pszPath
  1997. )
  1998. /*++
  1999. Routine Description:
  2000. Returns true if the given path looks syntactically valid.
  2001. This call is NOT network-aware.
  2002. Arguments:
  2003. pszPath - String containing a path.
  2004. Return Value:
  2005. TRUE if the path looks valid, otherwise FALSE.
  2006. --*/
  2007. {
  2008. return( ClRtlIsPathValid( pszPath ) );
  2009. } // ResUtilIsPathValid
  2010. DWORD
  2011. WINAPI
  2012. ResUtilFreeEnvironment(
  2013. IN LPVOID lpEnvironment
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. Destroys an environment variable block.
  2018. Arguments:
  2019. Environment - the environment variable block to destroy.
  2020. Return Value:
  2021. A Win32 error code.
  2022. --*/
  2023. {
  2024. NTSTATUS ntStatus;
  2025. ntStatus = RtlDestroyEnvironment( lpEnvironment );
  2026. return( RtlNtStatusToDosError(ntStatus) );
  2027. } // ResUtilFreeEnvironment
  2028. LPWSTR
  2029. WINAPI
  2030. ResUtilExpandEnvironmentStrings(
  2031. IN LPCWSTR pszSrc
  2032. )
  2033. /*++
  2034. Routine Description:
  2035. Expands environment strings and returns an allocated buffer containing
  2036. the result.
  2037. Arguments:
  2038. pszSrc - Source string to expand.
  2039. Return Value:
  2040. A pointer to a buffer containing the value if successful.
  2041. NULL if unsuccessful. Call GetLastError() to get more details.
  2042. --*/
  2043. {
  2044. return( ClRtlExpandEnvironmentStrings( pszSrc ) );
  2045. } // ResUtilExpandEnvironmentStrings
  2046. /////////////////////////////////////////////////////////////////////////////
  2047. //++
  2048. //
  2049. // ResUtilSetResourceServiceEnvironment
  2050. //
  2051. // Description:
  2052. // Write an additional netname based environment for the specified
  2053. // service. SCM will add these vars to the target service's environment
  2054. // such that the hostname APIs (GetComputerName, et. al.) will provide
  2055. // the netname as the hostname instead of the normal hostname.
  2056. //
  2057. // Arguments:
  2058. // pszServiceName [IN]
  2059. // Name of service whose environment is to be augmented.
  2060. //
  2061. // hResource [IN]
  2062. // Handle to resource that is dependent on a netname resource.
  2063. //
  2064. // pfnLogEvent [IN]
  2065. // Pointer to a routine that handles the reporting of events from
  2066. // the resource DLL.
  2067. //
  2068. // hResourceHandle [IN]
  2069. // Handle of hResource for logging.
  2070. //
  2071. // Return Value:
  2072. // ERROR_SUCCESS
  2073. // The function completed successfully.
  2074. //
  2075. // Win32 error code
  2076. // The function failed.
  2077. //
  2078. //--
  2079. /////////////////////////////////////////////////////////////////////////////
  2080. DWORD WINAPI ResUtilSetResourceServiceEnvironment(
  2081. IN LPCWSTR pszServiceName,
  2082. IN HRESOURCE hResource,
  2083. IN PLOG_EVENT_ROUTINE pfnLogEvent,
  2084. IN RESOURCE_HANDLE hResourceHandle
  2085. )
  2086. {
  2087. DWORD sc = ERROR_SUCCESS;
  2088. DWORD cbEnvironment = 0;
  2089. PVOID pvEnvironment = NULL;
  2090. LPWSTR pszEnvString = NULL;
  2091. HKEY hkeyServicesKey = NULL;
  2092. HKEY hkeyServiceName = NULL;
  2093. LPWSTR pszNetworkName = NULL;
  2094. DWORD cchNetworkNameBufferSize = 0;
  2095. //
  2096. // get the Name property from the netname resource represented by
  2097. // hResource
  2098. //
  2099. cchNetworkNameBufferSize = ScGetNameFromNetnameResource( hResource, &pszNetworkName );
  2100. if ( pszNetworkName == NULL )
  2101. {
  2102. sc = GetLastError();
  2103. (pfnLogEvent)(
  2104. hResourceHandle,
  2105. LOG_ERROR,
  2106. L"ResUtilSetResourceServiceEnvironment: Failed to get the Name property "
  2107. L"of this resource, error = %1!u!.\n",
  2108. sc
  2109. );
  2110. goto Cleanup;
  2111. }
  2112. //
  2113. // now get only the env. vars that cause the hostname APIs to report the
  2114. // netname as the hostname
  2115. //
  2116. sc = ScBuildNetNameEnvironment( pszNetworkName, cchNetworkNameBufferSize, &pvEnvironment );
  2117. if ( sc != ERROR_SUCCESS )
  2118. {
  2119. (pfnLogEvent)(
  2120. hResourceHandle,
  2121. LOG_ERROR,
  2122. L"ResUtilSetResourceServiceEnvironment: Failed to build the target service's "
  2123. L"environment for this resource, error = %1!u!.\n",
  2124. sc
  2125. );
  2126. goto Cleanup;
  2127. }
  2128. //
  2129. // Compute the size of the environment. We are looking for
  2130. // the double NULL terminator that ends the environment block.
  2131. //
  2132. pszEnvString = (LPWSTR) pvEnvironment;
  2133. while ( *pszEnvString != L'\0' )
  2134. {
  2135. while ( *pszEnvString++ != L'\0')
  2136. {
  2137. } // while: more characters in this environment string
  2138. } // while: more environment strings
  2139. cbEnvironment = (DWORD)((PUCHAR)pszEnvString - (PUCHAR)pvEnvironment) + sizeof( WCHAR );
  2140. //
  2141. // Open the Services key in the registry.
  2142. //
  2143. sc = RegOpenKeyExW(
  2144. HKEY_LOCAL_MACHINE,
  2145. L"System\\CurrentControlSet\\Services",
  2146. 0,
  2147. KEY_READ,
  2148. &hkeyServicesKey
  2149. );
  2150. if ( sc != ERROR_SUCCESS )
  2151. {
  2152. (pfnLogEvent)(
  2153. hResourceHandle,
  2154. LOG_ERROR,
  2155. L"ResUtilSetResourceServiceEnvironment: Failed to open services key, error = %1!u!.\n",
  2156. sc
  2157. );
  2158. goto Cleanup;
  2159. } // if: error opening the Services key in the registry
  2160. //
  2161. // Open the service name key in the registry
  2162. //
  2163. sc = RegOpenKeyExW(
  2164. hkeyServicesKey,
  2165. pszServiceName,
  2166. 0,
  2167. KEY_READ | KEY_WRITE,
  2168. &hkeyServiceName
  2169. );
  2170. RegCloseKey( hkeyServicesKey );
  2171. if ( sc != ERROR_SUCCESS )
  2172. {
  2173. (pfnLogEvent)(
  2174. hResourceHandle,
  2175. LOG_ERROR,
  2176. L"ResUtilSetResourceServiceEnvironment: Failed to open service key, error = %1!u!.\n",
  2177. sc
  2178. );
  2179. goto Cleanup;
  2180. } // if: error opening the service name key in the registry
  2181. //
  2182. // Set the environment value in the service's registry key.
  2183. //
  2184. sc = RegSetValueExW(
  2185. hkeyServiceName,
  2186. L"Environment",
  2187. 0,
  2188. REG_MULTI_SZ,
  2189. (const BYTE *) pvEnvironment,
  2190. cbEnvironment
  2191. );
  2192. RegCloseKey( hkeyServiceName );
  2193. if ( sc != ERROR_SUCCESS )
  2194. {
  2195. (pfnLogEvent)(
  2196. hResourceHandle,
  2197. LOG_ERROR,
  2198. L"ResUtilSetResourceServiceEnvironment: Failed to set service environment value, error = %1!u!.\n",
  2199. sc
  2200. );
  2201. goto Cleanup;
  2202. } // if: error setting the Environment value in the registry
  2203. Cleanup:
  2204. LocalFree( pszNetworkName );
  2205. if ( pvEnvironment != NULL )
  2206. {
  2207. ResUtilFreeEnvironment( pvEnvironment );
  2208. } // if: environment block allocated
  2209. return sc;
  2210. } //*** ResUtilSetResourceServiceEnvironment()
  2211. /////////////////////////////////////////////////////////////////////////////
  2212. //++
  2213. //
  2214. // ResUtilRemoveResourceServiceEnvironment
  2215. //
  2216. // Description:
  2217. // Remove the "netname" environment variables for the specified service.
  2218. //
  2219. // Arguments:
  2220. // pszServiceName [IN]
  2221. // Name of service whose environment is to be set.
  2222. //
  2223. // pfnLogEvent [IN]
  2224. // Pointer to a routine that handles the reporting of events from
  2225. // the resource DLL.
  2226. //
  2227. // hResourceHandle [IN]
  2228. // Handle for logging.
  2229. //
  2230. // Return Value:
  2231. // ERROR_SUCCESS
  2232. // The function completed successfully.
  2233. //
  2234. // Win32 error code
  2235. // The function failed.
  2236. //
  2237. //--
  2238. /////////////////////////////////////////////////////////////////////////////
  2239. DWORD WINAPI ResUtilRemoveResourceServiceEnvironment(
  2240. IN LPCWSTR pszServiceName,
  2241. IN PLOG_EVENT_ROUTINE pfnLogEvent,
  2242. IN RESOURCE_HANDLE hResourceHandle
  2243. )
  2244. {
  2245. DWORD sc;
  2246. HKEY hkeyServicesKey;
  2247. HKEY hkeyServiceName;
  2248. //
  2249. // Open the Services key in the registry.
  2250. //
  2251. sc = RegOpenKeyExW(
  2252. HKEY_LOCAL_MACHINE,
  2253. L"System\\CurrentControlSet\\Services",
  2254. 0,
  2255. KEY_READ,
  2256. &hkeyServicesKey
  2257. );
  2258. if ( sc != ERROR_SUCCESS )
  2259. {
  2260. (pfnLogEvent)(
  2261. hResourceHandle,
  2262. LOG_ERROR,
  2263. L"ResUtilRemoveResourceServiceEnvironment: Failed to open Services key, error = %1!u!.\n",
  2264. sc
  2265. );
  2266. goto Cleanup;
  2267. } // if: error opening the Services key in the registry
  2268. //
  2269. // Open the service name key in the registry
  2270. //
  2271. sc = RegOpenKeyExW(
  2272. hkeyServicesKey,
  2273. pszServiceName,
  2274. 0,
  2275. KEY_READ | KEY_WRITE,
  2276. &hkeyServiceName
  2277. );
  2278. RegCloseKey( hkeyServicesKey );
  2279. if ( sc != ERROR_SUCCESS )
  2280. {
  2281. (pfnLogEvent)(
  2282. hResourceHandle,
  2283. LOG_ERROR,
  2284. L"ResUtilRemoveResourceServiceEnvironment: Failed to open %1!ws! key, error = %2!u!.\n",
  2285. pszServiceName,
  2286. sc
  2287. );
  2288. goto Cleanup;
  2289. } // if: error opening the service name key in the registry
  2290. //
  2291. // Delete the environment value in the service's registry key.
  2292. //
  2293. sc = RegDeleteValueW(
  2294. hkeyServiceName,
  2295. L"Environment"
  2296. );
  2297. RegCloseKey( hkeyServiceName );
  2298. if ( sc != ERROR_SUCCESS )
  2299. {
  2300. (pfnLogEvent)(
  2301. hResourceHandle,
  2302. LOG_WARNING,
  2303. L"ResUtilRemoveResourceServiceEnvironment: Failed to remove environment "
  2304. L"value from service %1!ws!, error = %1!u!.\n",
  2305. pszServiceName,
  2306. sc
  2307. );
  2308. goto Cleanup;
  2309. } // if: error setting the Environment value in the registry
  2310. Cleanup:
  2311. return sc;
  2312. } //*** ResUtilRemoveResourceServiceEnvironment()
  2313. /////////////////////////////////////////////////////////////////////////////
  2314. //++
  2315. //
  2316. // ResUtilSetResourceServiceStartParameters
  2317. //
  2318. // Description:
  2319. // Set the start parameters for the specified service.
  2320. //
  2321. // Arguments:
  2322. // pszServiceName [IN]
  2323. // Name of service whose start parameters are to be set.
  2324. //
  2325. // schSCMHandle [IN]
  2326. // Handle to the Service Control Manager. Can be specified as NULL.
  2327. //
  2328. // phService [OUT]
  2329. // Service handle.
  2330. //
  2331. // pfnLogEvent [IN]
  2332. // Pointer to a routine that handles the reporting of events from
  2333. // the resource DLL.
  2334. //
  2335. // hResourceHandle [IN]
  2336. // Handle for logging.
  2337. //
  2338. // Return Value:
  2339. // ERROR_SUCCESS
  2340. // The function completed successfully.
  2341. //
  2342. // Win32 error code
  2343. // The function failed.
  2344. //
  2345. //--
  2346. /////////////////////////////////////////////////////////////////////////////
  2347. DWORD WINAPI ResUtilSetResourceServiceStartParameters(
  2348. IN LPCWSTR pszServiceName,
  2349. IN SC_HANDLE schSCMHandle,
  2350. IN OUT LPSC_HANDLE phService,
  2351. IN PLOG_EVENT_ROUTINE pfnLogEvent,
  2352. IN RESOURCE_HANDLE hResourceHandle
  2353. )
  2354. {
  2355. DWORD sc;
  2356. DWORD cbBytesNeeded;
  2357. DWORD cbQueryServiceConfig;
  2358. DWORD idx;
  2359. BOOL bWeOpenedSCM = FALSE;
  2360. LPQUERY_SERVICE_CONFIG pQueryServiceConfig = NULL;
  2361. LPSERVICE_FAILURE_ACTIONS pSvcFailureActions = NULL;
  2362. //
  2363. // Open the Service Control Manager if necessary.
  2364. //
  2365. if ( schSCMHandle == NULL )
  2366. {
  2367. schSCMHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  2368. if ( schSCMHandle == NULL )
  2369. {
  2370. sc = GetLastError();
  2371. (pfnLogEvent)(
  2372. hResourceHandle,
  2373. LOG_ERROR,
  2374. L"ResUtilSetResourceServiceStartParameters: Failed to open Service Control Manager. Error: %1!u!.\n",
  2375. sc
  2376. );
  2377. goto Cleanup;
  2378. } // if: error opening the Service Control Manager
  2379. bWeOpenedSCM = TRUE;
  2380. } // if: Service Control Manager not open yet
  2381. //
  2382. // Open the service.
  2383. //
  2384. *phService = OpenService(
  2385. schSCMHandle,
  2386. pszServiceName,
  2387. SERVICE_ALL_ACCESS
  2388. );
  2389. if ( *phService == NULL )
  2390. {
  2391. sc = GetLastError();
  2392. // TODO: Log event to the event log.
  2393. (pfnLogEvent)(
  2394. hResourceHandle,
  2395. LOG_ERROR,
  2396. L"ResUtilSetResourceServiceStartParameters: Failed to open the '%1' service. Error: %2!u!.\n",
  2397. pszServiceName,
  2398. sc
  2399. );
  2400. goto Cleanup;
  2401. } // if: error opening the service
  2402. //
  2403. // Query the service to make sure it is not disabled.
  2404. //
  2405. cbQueryServiceConfig = sizeof( QUERY_SERVICE_CONFIG );
  2406. do
  2407. {
  2408. //
  2409. // Allocate memory for the config info structure.
  2410. //
  2411. pQueryServiceConfig = (LPQUERY_SERVICE_CONFIG) LocalAlloc( LMEM_FIXED, cbQueryServiceConfig );
  2412. if ( pQueryServiceConfig == NULL )
  2413. {
  2414. sc = GetLastError();
  2415. (pfnLogEvent)(
  2416. hResourceHandle,
  2417. LOG_ERROR,
  2418. L"ResUtilSetResourceServiceStartParameters: Failed to allocate memory for query_service_config. Error: %1!u!.\n",
  2419. sc
  2420. );
  2421. break;
  2422. } // if: error allocating memory
  2423. //
  2424. // Query for the config info. If it fails because the buffer
  2425. // is too small, reallocate and try again.
  2426. //
  2427. if ( ! QueryServiceConfig(
  2428. *phService,
  2429. pQueryServiceConfig,
  2430. cbQueryServiceConfig,
  2431. &cbBytesNeeded
  2432. ) )
  2433. {
  2434. sc = GetLastError();
  2435. if ( sc != ERROR_INSUFFICIENT_BUFFER )
  2436. {
  2437. (pfnLogEvent)(
  2438. hResourceHandle,
  2439. LOG_ERROR,
  2440. L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for the '%1' service. Error: %2!u!.\n",
  2441. pszServiceName,
  2442. sc
  2443. );
  2444. break;
  2445. }
  2446. sc = ERROR_SUCCESS;
  2447. LocalFree( pQueryServiceConfig );
  2448. pQueryServiceConfig = NULL;
  2449. cbQueryServiceConfig = cbBytesNeeded;
  2450. continue;
  2451. } // if: error querying for service config info
  2452. else
  2453. {
  2454. sc = ERROR_SUCCESS;
  2455. cbBytesNeeded = 0;
  2456. } // else: query was successful
  2457. //
  2458. // Check to see if the service is disabled or not.
  2459. //
  2460. if ( pQueryServiceConfig->dwStartType == SERVICE_DISABLED )
  2461. {
  2462. (pfnLogEvent)(
  2463. hResourceHandle,
  2464. LOG_ERROR,
  2465. L"ResUtilSetResourceServiceStartParameters: The service '%1' is DISABLED.\n",
  2466. pszServiceName
  2467. );
  2468. sc = ERROR_SERVICE_DISABLED;
  2469. break;
  2470. } // if: service is disabled
  2471. } while ( cbBytesNeeded != 0 );
  2472. if ( sc != ERROR_SUCCESS )
  2473. {
  2474. goto Cleanup;
  2475. } // if: error occurred checking to see if service is disabled
  2476. //
  2477. // Set the service to manual start.
  2478. //
  2479. if ( ! ChangeServiceConfig(
  2480. *phService,
  2481. SERVICE_NO_CHANGE,
  2482. SERVICE_DEMAND_START, // Manual start
  2483. SERVICE_NO_CHANGE,
  2484. NULL,
  2485. NULL,
  2486. NULL,
  2487. NULL,
  2488. NULL,
  2489. NULL,
  2490. NULL
  2491. ) )
  2492. {
  2493. sc = GetLastError();
  2494. (pfnLogEvent)(
  2495. hResourceHandle,
  2496. LOG_ERROR,
  2497. L"ResUtilSetResourceServiceStartParameters: Failed to set service '%1' to manual start. Error: %2!u!.\n",
  2498. pszServiceName,
  2499. sc
  2500. );
  2501. goto Cleanup;
  2502. } // if: error setting service to manual start
  2503. //
  2504. // Query for the size of the service failure actions array.
  2505. // Use sc as the dummy buffer since the QueryServiceConfig2 API
  2506. // is not that friendly.
  2507. //
  2508. if ( ! QueryServiceConfig2(
  2509. *phService,
  2510. SERVICE_CONFIG_FAILURE_ACTIONS,
  2511. (LPBYTE) &sc,
  2512. sizeof( DWORD ),
  2513. &cbBytesNeeded
  2514. ) )
  2515. {
  2516. sc = GetLastError();
  2517. if ( sc == ERROR_INSUFFICIENT_BUFFER )
  2518. {
  2519. sc = ERROR_SUCCESS;
  2520. } // if: expected "buffer too small" error occurred
  2521. else
  2522. {
  2523. (pfnLogEvent)(
  2524. hResourceHandle,
  2525. LOG_ERROR,
  2526. L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for size for the '%1' service. Error: %2!u!.\n",
  2527. pszServiceName,
  2528. sc
  2529. );
  2530. goto Cleanup;
  2531. } // else: an unexpected error occurred
  2532. } // if: error querying for service failure actions buffer size
  2533. //
  2534. // Allocate memory for the service failure actions array.
  2535. //
  2536. pSvcFailureActions = (LPSERVICE_FAILURE_ACTIONS) LocalAlloc( LMEM_FIXED, cbBytesNeeded );
  2537. if ( pSvcFailureActions == NULL )
  2538. {
  2539. sc = GetLastError();
  2540. (pfnLogEvent)(
  2541. hResourceHandle,
  2542. LOG_ERROR,
  2543. L"ResUtilSetResourceServiceStartParameters: Failed to allocate memory of size %1!u!. Error: %2!u!.\n",
  2544. cbBytesNeeded,
  2545. sc
  2546. );
  2547. goto Cleanup;
  2548. } // if: error allocating memory for the service failure actions array
  2549. //
  2550. // Query for the service failure actions array.
  2551. //
  2552. if ( ! QueryServiceConfig2(
  2553. *phService,
  2554. SERVICE_CONFIG_FAILURE_ACTIONS,
  2555. (LPBYTE) pSvcFailureActions,
  2556. cbBytesNeeded,
  2557. &cbBytesNeeded
  2558. ) )
  2559. {
  2560. sc = GetLastError();
  2561. (pfnLogEvent)(
  2562. hResourceHandle,
  2563. LOG_ERROR,
  2564. L"ResUtilSetResourceServiceStartParameters: Failed to query service configuration for the '%1' service. Error: %2!u!.\n",
  2565. pszServiceName,
  2566. sc
  2567. );
  2568. goto Cleanup;
  2569. } // if: error querying for service failure actions
  2570. //
  2571. // If any of the service action is set to service restart,
  2572. // set it to none.
  2573. //
  2574. for ( idx = 0 ; idx < pSvcFailureActions->cActions ; idx++ )
  2575. {
  2576. if ( pSvcFailureActions->lpsaActions[ idx ].Type == SC_ACTION_RESTART )
  2577. {
  2578. pSvcFailureActions->lpsaActions[ idx ].Type = SC_ACTION_NONE;
  2579. } // if: action set to restart
  2580. } // for: each service failure action array entry
  2581. //
  2582. // Set the changes to the service failure actions array.
  2583. //
  2584. if ( ! ChangeServiceConfig2(
  2585. *phService,
  2586. SERVICE_CONFIG_FAILURE_ACTIONS,
  2587. pSvcFailureActions
  2588. ) )
  2589. {
  2590. sc = GetLastError();
  2591. (pfnLogEvent)(
  2592. hResourceHandle,
  2593. LOG_ERROR,
  2594. L"ResUtilSetResourceServiceStartParameters: Failed to set service failure actions for the '%1' service. Error: %2!u!.\n",
  2595. pszServiceName,
  2596. sc
  2597. );
  2598. goto Cleanup;
  2599. } // if: error saving service failure actions
  2600. Cleanup:
  2601. //
  2602. // Cleanup.
  2603. //
  2604. LocalFree( pQueryServiceConfig );
  2605. LocalFree( pSvcFailureActions );
  2606. if ( bWeOpenedSCM )
  2607. {
  2608. CloseServiceHandle( schSCMHandle );
  2609. } // if: we opened the Server Control Manager
  2610. if ( ( sc != ERROR_SUCCESS ) && ( *phService != NULL ) )
  2611. {
  2612. CloseServiceHandle( *phService );
  2613. *phService = NULL;
  2614. } // if: error occurred after opening service
  2615. return sc;
  2616. } //*** ResUtilSetResourceServiceStartParameters()
  2617. /////////////////////////////////////////////////////////////////////////////
  2618. //++
  2619. //
  2620. // ResUtilGetResourceDependentIPAddressProps
  2621. //
  2622. // Description:
  2623. // Get the properties from the first IP Address resource on which the
  2624. // specified resource is dependent.
  2625. //
  2626. // Arguments:
  2627. // hResource [IN]
  2628. // Handle to the resource to query.
  2629. //
  2630. // pszAddress [OUT]
  2631. // Output buffer for returning the address.
  2632. //
  2633. // pcchAddress [IN OUT]
  2634. // On input contains the size in characters of the pszAddress buffer.
  2635. // On output contains the size in characters, including the terminating
  2636. // NULL, of the string for the Address property. If pszAddress is
  2637. // specified as NULL and this is not specified as NULL, ERROR_SUCCESS
  2638. // be returned. Otherwise, ERROR_MORE_DATA will be returned.
  2639. //
  2640. // pszSubnetMask [OUT]
  2641. // Output buffer for returning the subnet mask.
  2642. //
  2643. // pcchSubnetMask [IN OUT]
  2644. // On input contains the size in characters of the pszSubnetMask buffer.
  2645. // On output contains the size in characters, including the terminating
  2646. // NULL, of the string for the SubnetMask property. If pszSubnetMask is
  2647. // specified as NULL and this is not specified as NULL, ERROR_SUCCESS
  2648. // be returned. Otherwise, ERROR_MORE_DATA will be returned.
  2649. //
  2650. // pszNetwork [OUT]
  2651. // Output buffer for returning the network.
  2652. //
  2653. // pcchNetwork [IN OUT]
  2654. // On input contains the size in characters of the pszNetwork buffer.
  2655. // On output contains the size in characters, including the terminating
  2656. // NULL, of the string for the Network property. If pszNetwork is
  2657. // specified as NULL and this is not specified as NULL, ERROR_SUCCESS
  2658. // be returned. Otherwise, ERROR_MORE_DATA will be returned.
  2659. //
  2660. // Return Value:
  2661. // ERROR_SUCCESS
  2662. // The function completed successfully.
  2663. //
  2664. // ERROR_MORE_DATA
  2665. // The size of one of the buffers was too small.
  2666. //
  2667. // Win32 error code
  2668. // The function failed.
  2669. //
  2670. //--
  2671. /////////////////////////////////////////////////////////////////////////////
  2672. DWORD WINAPI ResUtilGetResourceDependentIPAddressProps(
  2673. IN HRESOURCE hResource,
  2674. OUT LPWSTR pszAddress,
  2675. IN OUT DWORD * pcchAddress,
  2676. OUT LPWSTR pszSubnetMask,
  2677. IN OUT DWORD * pcchSubnetMask,
  2678. OUT LPWSTR pszNetwork,
  2679. IN OUT DWORD * pcchNetwork
  2680. )
  2681. {
  2682. DWORD sc = ERROR_SUCCESS;
  2683. HRESENUM hresenum = NULL;
  2684. HRESOURCE hresDep = NULL;
  2685. DWORD idx;
  2686. DWORD nType;
  2687. DWORD cchmacName;
  2688. DWORD cchName;
  2689. LPWSTR pszName = NULL;
  2690. DWORD cbProps;
  2691. PBYTE pbProps = NULL;
  2692. LPWSTR pszProp;
  2693. DWORD cchProp;
  2694. HCLUSTER hCluster;
  2695. HRESULT hr;
  2696. //
  2697. // Enumerate dependent resources.
  2698. //
  2699. hresenum = ClusterResourceOpenEnum( hResource, CLUSTER_RESOURCE_ENUM_DEPENDS );
  2700. if ( hresenum == NULL )
  2701. {
  2702. sc = GetLastError();
  2703. goto Cleanup;
  2704. } // if: error opening the enumeration
  2705. //
  2706. // Allocate the initial name buffer.
  2707. //
  2708. cchmacName = 256;
  2709. cchName = cchmacName;
  2710. pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
  2711. if ( pszName == NULL )
  2712. {
  2713. sc = GetLastError();
  2714. goto Cleanup;
  2715. } // if: error allocating resource name buffer
  2716. for ( idx = 0 ; ; idx++ )
  2717. {
  2718. //
  2719. // Get the first entry in the enumeration.
  2720. //
  2721. sc = ClusterResourceEnum(
  2722. hresenum,
  2723. idx,
  2724. &nType,
  2725. pszName,
  2726. &cchName
  2727. );
  2728. if ( sc == ERROR_MORE_DATA )
  2729. {
  2730. LocalFree( pszName );
  2731. cchName++;
  2732. cchmacName = cchName;
  2733. pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
  2734. if ( pszName == NULL )
  2735. {
  2736. sc = GetLastError();
  2737. break;
  2738. } // if: error allocating resource name buffer
  2739. sc = ClusterResourceEnum(
  2740. hresenum,
  2741. idx,
  2742. &nType,
  2743. pszName,
  2744. &cchName
  2745. );
  2746. } // if: buffer is too small
  2747. if ( sc != ERROR_SUCCESS )
  2748. {
  2749. break;
  2750. } // if: error getting the dependent resource name
  2751. //
  2752. // Open the resource.
  2753. //
  2754. hCluster = GetClusterFromResource( hResource );
  2755. if ( hCluster == NULL ) {
  2756. sc = GetLastError();
  2757. break;
  2758. }
  2759. hresDep = OpenClusterResource( hCluster, pszName );
  2760. if ( hresDep == NULL )
  2761. {
  2762. sc = GetLastError();
  2763. break;
  2764. } // if: error opening the dependent resource
  2765. //
  2766. // Get the resource type name.
  2767. //
  2768. cchName = cchmacName;
  2769. sc = ClusterResourceControl(
  2770. hresDep,
  2771. NULL,
  2772. CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
  2773. NULL,
  2774. 0,
  2775. pszName,
  2776. cchmacName,
  2777. &cchName
  2778. );
  2779. if ( sc == ERROR_MORE_DATA )
  2780. {
  2781. LocalFree( pszName );
  2782. cchName++;
  2783. cchmacName = cchName;
  2784. pszName = (LPWSTR) LocalAlloc( LMEM_FIXED, cchName * sizeof( pszName[ 0 ] ) );
  2785. if ( pszName == NULL )
  2786. {
  2787. sc = GetLastError();
  2788. break;
  2789. } // if: error allocating resource type name buffer
  2790. sc = ClusterResourceControl(
  2791. hresDep,
  2792. NULL,
  2793. CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
  2794. NULL,
  2795. 0,
  2796. pszName,
  2797. cchmacName,
  2798. &cchName
  2799. );
  2800. } // if: buffer was too small
  2801. if ( sc != ERROR_SUCCESS )
  2802. {
  2803. break;
  2804. } // if: error getting resource type name
  2805. if ( ClRtlStrNICmp( pszName, CLUS_RESTYPE_NAME_IPADDR, RTL_NUMBER_OF( CLUS_RESTYPE_NAME_IPADDR ) ) == 0 )
  2806. {
  2807. //
  2808. // Get the private properties of the dependent resource.
  2809. //
  2810. cbProps = 1024;
  2811. pbProps = (PBYTE) LocalAlloc( LMEM_FIXED, cbProps );
  2812. if ( pbProps == NULL )
  2813. {
  2814. sc = GetLastError();
  2815. break;
  2816. } // if: error allocating buffer for properties
  2817. sc = ClusterResourceControl(
  2818. hresDep,
  2819. NULL,
  2820. CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
  2821. NULL,
  2822. 0,
  2823. pbProps,
  2824. cbProps,
  2825. &cbProps
  2826. );
  2827. if ( sc == ERROR_MORE_DATA )
  2828. {
  2829. LocalFree( pbProps );
  2830. pbProps = (PBYTE) LocalAlloc( LMEM_FIXED, cbProps );
  2831. if ( pbProps == NULL )
  2832. {
  2833. sc = GetLastError();
  2834. break;
  2835. } // if: error allocating buffer for properties
  2836. sc = ClusterResourceControl(
  2837. hresDep,
  2838. NULL,
  2839. CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
  2840. NULL,
  2841. 0,
  2842. pbProps,
  2843. cbProps,
  2844. &cbProps
  2845. );
  2846. } // if: properties buffer too small
  2847. if ( sc != ERROR_SUCCESS )
  2848. {
  2849. break;
  2850. } // if: error getting private properties
  2851. //
  2852. // Return the address.
  2853. //
  2854. if ( ( pszAddress != NULL )
  2855. || ( pcchAddress != NULL )
  2856. )
  2857. {
  2858. sc = ResUtilFindSzProperty(
  2859. pbProps,
  2860. cbProps,
  2861. L"Address",
  2862. &pszProp
  2863. );
  2864. if ( sc != ERROR_SUCCESS )
  2865. {
  2866. break;
  2867. } // if: error finding the property
  2868. cchProp = (DWORD) wcslen( pszProp ) + 1;
  2869. if ( cchProp > *pcchAddress )
  2870. {
  2871. if ( pszAddress == NULL )
  2872. {
  2873. sc = ERROR_SUCCESS;
  2874. } // if: no buffer was specified
  2875. else
  2876. {
  2877. sc = ERROR_MORE_DATA;
  2878. } // else: buffer was specified but was too small
  2879. *pcchAddress = cchProp;
  2880. break;
  2881. } // if: buffer is too small
  2882. hr = StringCchCopy( pszAddress, *pcchAddress, pszProp );
  2883. if ( FAILED( hr ) )
  2884. {
  2885. sc = HRESULT_CODE( hr );
  2886. break;
  2887. }
  2888. *pcchAddress = cchProp;
  2889. } // if: address requested by caller
  2890. //
  2891. // Return the subnet mask.
  2892. //
  2893. if ( ( pszSubnetMask != NULL )
  2894. || ( pcchSubnetMask != NULL )
  2895. )
  2896. {
  2897. sc = ResUtilFindSzProperty(
  2898. pbProps,
  2899. cbProps,
  2900. L"SubnetMask",
  2901. &pszProp
  2902. );
  2903. if ( sc != ERROR_SUCCESS )
  2904. {
  2905. break;
  2906. } // if: error finding the property
  2907. cchProp = (DWORD) wcslen( pszProp ) + 1;
  2908. if ( cchProp > *pcchSubnetMask )
  2909. {
  2910. if ( pszSubnetMask == NULL )
  2911. {
  2912. sc = ERROR_SUCCESS;
  2913. } // if: no buffer was specified
  2914. else
  2915. {
  2916. sc = ERROR_MORE_DATA;
  2917. } // else: buffer was specified but was too small
  2918. *pcchSubnetMask = cchProp;
  2919. break;
  2920. } // if: buffer is too small
  2921. hr = StringCchCopy( pszSubnetMask, *pcchSubnetMask, pszProp );
  2922. if ( FAILED( hr ) )
  2923. {
  2924. sc = HRESULT_CODE( hr );
  2925. break;
  2926. }
  2927. *pcchSubnetMask = cchProp;
  2928. } // if: subnet mask requested by caller
  2929. //
  2930. // Return the network.
  2931. //
  2932. if ( ( pszNetwork != NULL )
  2933. || ( pcchNetwork != NULL )
  2934. )
  2935. {
  2936. sc = ResUtilFindSzProperty(
  2937. pbProps,
  2938. cbProps,
  2939. L"Network",
  2940. &pszProp
  2941. );
  2942. if ( sc != ERROR_SUCCESS )
  2943. {
  2944. break;
  2945. } // if: error finding the property
  2946. cchProp = (DWORD) wcslen( pszProp ) + 1;
  2947. if ( cchProp > *pcchNetwork )
  2948. {
  2949. if ( pszNetwork == NULL )
  2950. {
  2951. sc = ERROR_SUCCESS;
  2952. } // if: no buffer was specified
  2953. else
  2954. {
  2955. sc = ERROR_MORE_DATA;
  2956. } // else: buffer was specified but was too small
  2957. *pcchNetwork = cchProp;
  2958. break;
  2959. } // if: buffer is too small
  2960. hr = StringCchCopy( pszNetwork, *pcchNetwork, pszProp );
  2961. if ( FAILED( hr ) )
  2962. {
  2963. sc = HRESULT_CODE( hr );
  2964. break;
  2965. }
  2966. *pcchNetwork = cchProp;
  2967. } // if: network requested by caller
  2968. //
  2969. // Exit the loop since we found a match.
  2970. //
  2971. break;
  2972. } // if: IP Address resource found
  2973. //
  2974. // Close the dependent resource.
  2975. //
  2976. CloseClusterResource( hresDep );
  2977. hresDep = NULL;
  2978. } // for: each dependency
  2979. Cleanup:
  2980. //
  2981. // Cleanup.
  2982. //
  2983. LocalFree( pszName );
  2984. LocalFree( pbProps );
  2985. if ( hresenum != NULL )
  2986. {
  2987. ClusterResourceCloseEnum( hresenum );
  2988. } // if: we opened the enumerator
  2989. if ( hresDep != NULL )
  2990. {
  2991. CloseClusterResource( hresDep );
  2992. } // if: opened dependent resource
  2993. return sc;
  2994. } //*** ResUtilGetResourceDependentIPAddressProps()
  2995. /////////////////////////////////////////////////////////////////////////////
  2996. //++
  2997. //
  2998. // ResUtilFindDependentDiskResourceDriveLetter
  2999. //
  3000. // Description:
  3001. // Finds a disk resource in the dependent resources and retrieves the
  3002. // the drive letter associated with it.
  3003. //
  3004. // Arguments:
  3005. // hCluster [IN]
  3006. // Handle to the cluster.
  3007. //
  3008. // hResource [IN]
  3009. // Handle to the resource to query for dependencies.
  3010. //
  3011. // pszDriveLetter [IN/RETVAL]
  3012. // The drive letter of a dependent disk resource that was found.
  3013. // If a resource is not found, this value is untouched.
  3014. //
  3015. // pcchDriverLetter [IN/OUT]
  3016. // [IN] The number of characters that pszDriverLetter points to.
  3017. // [OUT] The number of characters written to the buffer
  3018. // (including NULL). If ERROR_MORE_DATA is returned, this value
  3019. // is the size of the buffer required to store the value.
  3020. //
  3021. // Return Value:
  3022. // ERROR_SUCCESS
  3023. // The function completed successfully and the drive letter was
  3024. // set.
  3025. //
  3026. // ERROR_NO_MORE_ITEMS
  3027. // ERROR_RESOURCE_NOT_PRESENT
  3028. // A dependent disk resource was not found or the resource is
  3029. // not dependent on a disk resource.
  3030. //
  3031. // ERROR_MORE_DATA
  3032. // The buffer passed in is too small. pcchDriveLetter will
  3033. // contain the size of the buffer (WCHARs) needed to fulfill
  3034. // the request.
  3035. //
  3036. // Win32 error code
  3037. // Other possible failures.
  3038. //
  3039. // SPECIAL NOTE:
  3040. // Do _NOT_ call this from a Resource DLL. It will cause a deadlock.
  3041. // You should have your Resource Extension call this function and
  3042. // write the results out as a private property that your Resource
  3043. // DLL can then read.
  3044. //
  3045. //--
  3046. /////////////////////////////////////////////////////////////////////////////
  3047. DWORD WINAPI ResUtilFindDependentDiskResourceDriveLetter(
  3048. IN HCLUSTER hCluster, // handle to cluster
  3049. IN HRESOURCE hResource, // handle to resource to query for dependencies
  3050. IN LPWSTR pszDriveLetter, // buffer to store drive letter (ex. "X:")
  3051. IN OUT DWORD * pcchDriveLetter // IN size of the pszDriveLetter buffer, OUT size of buffer required
  3052. )
  3053. {
  3054. BOOL fFoundDriveLetter = FALSE;
  3055. DWORD status = ERROR_SUCCESS;
  3056. HRESENUM hresenum = NULL;
  3057. HRESOURCE hRes = NULL;
  3058. DWORD cchName;
  3059. DWORD dwRetType;
  3060. WCHAR szName[ MAX_PATH ];
  3061. INT iCount;
  3062. HRESULT hr;
  3063. PBYTE pDiskInfo = NULL;
  3064. // validate arguments
  3065. if ( !pszDriveLetter || !pcchDriveLetter )
  3066. {
  3067. status = ERROR_INVALID_PARAMETER;
  3068. goto Cleanup;
  3069. }
  3070. hresenum = ClusterResourceOpenEnum( hResource, CLUSTER_RESOURCE_ENUM_DEPENDS );
  3071. if ( hresenum != NULL )
  3072. {
  3073. // Scan the dependencies until we find a disk resource or we hit
  3074. // the end of the dependency list.
  3075. for( iCount = 0 ; ! fFoundDriveLetter && ( status == ERROR_SUCCESS ) ; iCount++ )
  3076. {
  3077. cchName = RTL_NUMBER_OF( szName );
  3078. status = ClusterResourceEnum( hresenum, iCount, &dwRetType, szName, &cchName );
  3079. if ( status == ERROR_SUCCESS )
  3080. {
  3081. // Interrogate the resource to see if it is a disk resource.
  3082. hRes = OpenClusterResource( hCluster, szName );
  3083. if ( hRes != NULL )
  3084. {
  3085. DWORD cbDiskInfo = sizeof(CLUSPROP_DWORD)
  3086. + sizeof(CLUSPROP_SCSI_ADDRESS)
  3087. + sizeof(CLUSPROP_DISK_NUMBER)
  3088. + sizeof(CLUSPROP_PARTITION_INFO)
  3089. + sizeof(CLUSPROP_SYNTAX);
  3090. pDiskInfo = (PBYTE) LocalAlloc( LMEM_FIXED, cbDiskInfo );
  3091. if ( !pDiskInfo )
  3092. {
  3093. status = ERROR_OUTOFMEMORY;
  3094. goto Cleanup;
  3095. } // if: !pDiskInfo
  3096. status = ClusterResourceControl( hRes,
  3097. NULL,
  3098. CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
  3099. NULL,
  3100. 0,
  3101. pDiskInfo,
  3102. cbDiskInfo,
  3103. &cbDiskInfo
  3104. );
  3105. if ( status == ERROR_MORE_DATA )
  3106. {
  3107. LocalFree( pDiskInfo );
  3108. // get a bigger block
  3109. pDiskInfo = (PBYTE) LocalAlloc( LMEM_FIXED, cbDiskInfo );
  3110. if ( !pDiskInfo )
  3111. {
  3112. status = ERROR_OUTOFMEMORY;
  3113. goto Cleanup;
  3114. } // if: !pDiskInfo
  3115. status = ClusterResourceControl( hRes,
  3116. NULL,
  3117. CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
  3118. NULL,
  3119. 0,
  3120. pDiskInfo,
  3121. cbDiskInfo,
  3122. &cbDiskInfo
  3123. );
  3124. } // if: more data
  3125. if ( status == ERROR_SUCCESS )
  3126. {
  3127. DWORD dwValueSize;
  3128. CLUSPROP_BUFFER_HELPER props;
  3129. PCLUSPROP_PARTITION_INFO pPartitionInfo;
  3130. props.pb = pDiskInfo;
  3131. // Loop through each property.
  3132. while ( ! fFoundDriveLetter
  3133. && ( status == ERROR_SUCCESS )
  3134. && ( cbDiskInfo > sizeof(CLUSPROP_SYNTAX ) )
  3135. && ( props.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) )
  3136. {
  3137. // Get the size of this value and verify there is enough buffer left.
  3138. dwValueSize = sizeof(*props.pValue) + ALIGN_CLUSPROP( props.pValue->cbLength );
  3139. if ( dwValueSize > cbDiskInfo )
  3140. {
  3141. goto Cleanup;
  3142. } // if: data is not valid
  3143. if ( props.pSyntax->dw == CLUSPROP_SYNTAX_PARTITION_INFO )
  3144. {
  3145. // Validate the data. There must be a device name.
  3146. pPartitionInfo = props.pPartitionInfoValue;
  3147. if ( ( dwValueSize != sizeof(*pPartitionInfo) )
  3148. || ( pPartitionInfo->szDeviceName[0] == L'\0' ) )
  3149. {
  3150. goto Cleanup;
  3151. } // if: data is not valid
  3152. // Make sure it fits
  3153. if ( wcslen( pPartitionInfo->szDeviceName ) < *pcchDriveLetter )
  3154. {
  3155. hr = StringCchCopy( pszDriveLetter, *pcchDriveLetter, pPartitionInfo->szDeviceName );
  3156. if ( FAILED( hr ) )
  3157. {
  3158. status = HRESULT_CODE( hr );
  3159. goto Cleanup;
  3160. }
  3161. fFoundDriveLetter = TRUE;
  3162. } // if: drive letter fits into buffer
  3163. else
  3164. {
  3165. status = ERROR_MORE_DATA;
  3166. } // else: does not fit into buffer
  3167. // set the size written and/or size needed
  3168. *pcchDriveLetter = (DWORD) wcslen( pPartitionInfo->szDeviceName ) + 1;
  3169. } // if props.pSyntax->dw
  3170. cbDiskInfo -= dwValueSize;
  3171. props.pb += dwValueSize;
  3172. } // while
  3173. } // if status
  3174. else if ( status == ERROR_INVALID_FUNCTION )
  3175. {
  3176. // Ignore resources that don't support the control
  3177. // code. Only storage-class resources will support
  3178. // the control code.
  3179. status = ERROR_SUCCESS;
  3180. } // else if: resource doesn't support the control code
  3181. LocalFree( pDiskInfo );
  3182. pDiskInfo = NULL;
  3183. CloseClusterResource( hRes );
  3184. hRes = NULL;
  3185. } // if hRes
  3186. } // if status
  3187. else if ( status == ERROR_NO_MORE_ITEMS )
  3188. {
  3189. goto Cleanup;
  3190. } // if status
  3191. } // for ( i )
  3192. ClusterResourceCloseEnum( hresenum );
  3193. hresenum = NULL;
  3194. } // if: opened hresenum
  3195. else
  3196. {
  3197. status = GetLastError( );
  3198. } // else: failed to open hresenum
  3199. Cleanup:
  3200. // Make sure if we did not find a disk resource that we don't
  3201. // return ERROR_SUCCESS or ERROR_NO_MORE_ITEMS.
  3202. if ( ! fFoundDriveLetter
  3203. && ( ( status == ERROR_SUCCESS )
  3204. || ( status == ERROR_NO_MORE_ITEMS ) ) )
  3205. {
  3206. status = ERROR_RESOURCE_NOT_PRESENT;
  3207. } // if: sanity check
  3208. LocalFree( pDiskInfo );
  3209. if ( hRes != NULL )
  3210. {
  3211. CloseClusterResource( hRes );
  3212. }
  3213. if ( hresenum != NULL )
  3214. {
  3215. ClusterResourceCloseEnum( hresenum );
  3216. }
  3217. return status;
  3218. } //*** ResUtilFindDependentDiskResourceDriveLetter()
  3219. //////////////////////////////////////////////////////////////////////////////
  3220. //++
  3221. //
  3222. // ScIsResourceOfType()
  3223. //
  3224. // Description:
  3225. // Is the resource of the type passed in?
  3226. //
  3227. // Arguments:
  3228. //
  3229. //
  3230. // Return Value:
  3231. // S_OK
  3232. // The resource is of the type requested.
  3233. //
  3234. // S_FALSE
  3235. // The resource is not of the type requested.
  3236. //
  3237. // Other HRESULT
  3238. // Win32 error as HRESULT.
  3239. //
  3240. // Remarks:
  3241. // None.
  3242. //
  3243. //--
  3244. //////////////////////////////////////////////////////////////////////////////
  3245. static DWORD
  3246. ScIsResourceOfType(
  3247. HRESOURCE hResIn
  3248. , const WCHAR * pszResourceTypeIn
  3249. , BOOL * pbIsResourceOfTypeOut
  3250. )
  3251. {
  3252. DWORD sc = ERROR_SUCCESS;
  3253. WCHAR * psz = NULL;
  3254. DWORD cbpsz = 33 * sizeof( WCHAR );
  3255. DWORD cb;
  3256. int idx;
  3257. if ( pbIsResourceOfTypeOut == NULL )
  3258. {
  3259. sc = ERROR_INVALID_PARAMETER;
  3260. goto Cleanup;
  3261. } // else
  3262. for ( idx = 0; idx < 2; idx++ )
  3263. {
  3264. psz = (WCHAR *) LocalAlloc( LPTR, cbpsz );
  3265. if ( psz == NULL )
  3266. {
  3267. sc = ERROR_NOT_ENOUGH_MEMORY;
  3268. goto Cleanup;
  3269. } // if:
  3270. sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, psz, cbpsz, &cb );
  3271. if ( sc == ERROR_MORE_DATA )
  3272. {
  3273. LocalFree( psz );
  3274. psz = NULL;
  3275. cbpsz = cb + 1;
  3276. continue;
  3277. } // if:
  3278. if ( sc != ERROR_SUCCESS )
  3279. {
  3280. goto Cleanup;
  3281. } // if:
  3282. break;
  3283. } // for:
  3284. *pbIsResourceOfTypeOut = ( ClRtlStrNICmp( psz, pszResourceTypeIn, (cbpsz / sizeof( WCHAR )) ) == 0 );
  3285. Cleanup:
  3286. LocalFree( psz );
  3287. return sc;
  3288. } //*** ScIsResourceOfType()
  3289. //////////////////////////////////////////////////////////////////////////////
  3290. //++
  3291. //
  3292. // ScIsCoreResource()
  3293. //
  3294. // Description:
  3295. // Is the passed in resource a core resource?
  3296. //
  3297. // Arguments:
  3298. //
  3299. //
  3300. // Return Value:
  3301. // ERROR_SUCCESS
  3302. // The operation succeeded.
  3303. //
  3304. // Other Win32 error
  3305. //
  3306. // Remarks:
  3307. // None.
  3308. //
  3309. //--
  3310. //////////////////////////////////////////////////////////////////////////////
  3311. static DWORD
  3312. ScIsCoreResource(
  3313. HRESOURCE hResIn
  3314. , BOOL * pfIsCoreResourceOut
  3315. )
  3316. {
  3317. DWORD sc;
  3318. DWORD dwFlags = 0;
  3319. DWORD cb;
  3320. BOOL fIsCoreResource = FALSE;
  3321. sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_FLAGS, NULL, 0, &dwFlags, sizeof( dwFlags ), &cb );
  3322. if ( sc != ERROR_SUCCESS )
  3323. {
  3324. goto Cleanup;
  3325. } // if:
  3326. fIsCoreResource = ( dwFlags & CLUS_FLAG_CORE );
  3327. if ( pfIsCoreResourceOut != NULL )
  3328. {
  3329. *pfIsCoreResourceOut = fIsCoreResource;
  3330. } // if:
  3331. else
  3332. {
  3333. sc = ERROR_INVALID_PARAMETER;
  3334. } // else
  3335. Cleanup:
  3336. return sc;
  3337. } //*** ScIsCoreResource()
  3338. //////////////////////////////////////////////////////////////////////////////
  3339. //++
  3340. //
  3341. // ScIsQuorumCapableResource()
  3342. //
  3343. // Description:
  3344. // Is the passed in resource quorum capable?
  3345. //
  3346. // Arguments:
  3347. // hResIn
  3348. // The resource to check for quorum capability.
  3349. //
  3350. // pfIsQuorumCapableResource
  3351. // True if the resource is quorum capable, false if it is not.
  3352. //
  3353. // Return Value:
  3354. // ERROR_SUCCESS
  3355. // The operation succeeded.
  3356. //
  3357. // Other Win32 error
  3358. //
  3359. // Remarks:
  3360. // None.
  3361. //
  3362. //--
  3363. //////////////////////////////////////////////////////////////////////////////
  3364. static DWORD
  3365. ScIsQuorumCapableResource(
  3366. HRESOURCE hResIn
  3367. , BOOL * pfIsQuorumCapableResource
  3368. )
  3369. {
  3370. DWORD sc;
  3371. DWORD cb;
  3372. DWORD dwFlags = 0;
  3373. if ( hResIn == NULL )
  3374. {
  3375. sc = ERROR_INVALID_PARAMETER;
  3376. goto Cleanup;
  3377. } // if:
  3378. if ( pfIsQuorumCapableResource == NULL )
  3379. {
  3380. sc = ERROR_INVALID_PARAMETER;
  3381. goto Cleanup;
  3382. } // if:
  3383. sc = ClusterResourceControl( hResIn, NULL, CLUSCTL_RESOURCE_GET_CHARACTERISTICS, NULL, 0, &dwFlags, sizeof( dwFlags ), &cb );
  3384. if ( sc != ERROR_SUCCESS )
  3385. {
  3386. goto Cleanup;
  3387. } // if:
  3388. *pfIsQuorumCapableResource = ( dwFlags & CLUS_CHAR_QUORUM );
  3389. Cleanup:
  3390. return sc;
  3391. } //*** ScIsQuorumCapableResource()
  3392. static WCHAR * g_pszCoreResourceTypes[] =
  3393. {
  3394. CLUS_RESTYPE_NAME_NETNAME,
  3395. CLUS_RESTYPE_NAME_IPADDR,
  3396. L"\0"
  3397. };
  3398. #define CLUSTER_NAME 0
  3399. #define CLUSTER_IP_ADDRESS 1
  3400. //////////////////////////////////////////////////////////////////////////////
  3401. //++
  3402. //
  3403. // ResUtilGetCoreClusterResources()
  3404. //
  3405. // Description:
  3406. // Find the core cluster resources.
  3407. //
  3408. // Arguments:
  3409. // hClusterIn
  3410. // The cluster whose core resource are sought.
  3411. //
  3412. // phClusterNameResourceOut
  3413. // The resource handle of the cluster name resource.
  3414. //
  3415. // phClusterIPAddressResourceOut
  3416. // The resource handle of the cluster IP address resource.
  3417. //
  3418. // phClusterQuorumResourceOut
  3419. // The resource handle of the cluster quorum resource.
  3420. //
  3421. // Return Value:
  3422. // ERROR_SUCCESS or other Win32 error.
  3423. //
  3424. // Remarks:
  3425. // None.
  3426. //
  3427. //--
  3428. //////////////////////////////////////////////////////////////////////////////
  3429. DWORD
  3430. WINAPI
  3431. ResUtilGetCoreClusterResources(
  3432. HCLUSTER hClusterIn
  3433. , HRESOURCE * phClusterNameResourceOut
  3434. , HRESOURCE * phClusterIPAddressResourceOut
  3435. , HRESOURCE * phClusterQuorumResourceOut
  3436. )
  3437. {
  3438. DWORD sc;
  3439. HCLUSENUM hEnum = NULL;
  3440. DWORD idxResource;
  3441. DWORD idx;
  3442. DWORD dwType;
  3443. WCHAR * psz = NULL;
  3444. DWORD cchpsz = 33;
  3445. DWORD cch;
  3446. HRESOURCE hRes = NULL;
  3447. BOOL fIsCoreResource = FALSE;
  3448. BOOL fIsResourceOfType = FALSE;
  3449. BOOL fCloseResource = FALSE;
  3450. BOOL fIsQuorumCapableResource = FALSE;
  3451. if ( hClusterIn == NULL )
  3452. {
  3453. sc = ERROR_INVALID_PARAMETER;
  3454. goto Cleanup;
  3455. } // if:
  3456. hEnum = ClusterOpenEnum( hClusterIn, CLUSTER_ENUM_RESOURCE );
  3457. if ( hEnum == NULL )
  3458. {
  3459. sc = GetLastError();
  3460. goto Cleanup;
  3461. } // if:
  3462. psz = (WCHAR *) LocalAlloc( LPTR, cchpsz * sizeof( WCHAR ) );
  3463. if ( psz == NULL )
  3464. {
  3465. sc = ERROR_NOT_ENOUGH_MEMORY;
  3466. goto Cleanup;
  3467. } // if:
  3468. //
  3469. // KB: 10-JUL-2002 GalenB
  3470. //
  3471. // Using cch in the ClusterEnum() call below because using cchpsz causes extra allocations.
  3472. // ClusterEnum() changes cch when the buffer is big enough to hold the data and returns
  3473. // ERROR_SUCCESS to be the size of the data that was just copied into the buffer. Now
  3474. // cch no longer reflects the amount of memory allocated to psz...
  3475. //
  3476. for ( idxResource = 0; ; )
  3477. {
  3478. //
  3479. // Reset cch to the real size of the buffer to avoid extra allocations...
  3480. //
  3481. cch = cchpsz;
  3482. sc = ClusterEnum( hEnum, idxResource, &dwType, psz, &cch );
  3483. if ( sc == ERROR_MORE_DATA )
  3484. {
  3485. LocalFree( psz );
  3486. psz = NULL;
  3487. cch++; // need space for the NULL...
  3488. cchpsz = cch;
  3489. psz = (WCHAR *) LocalAlloc( LPTR, cchpsz * sizeof( WCHAR ) );
  3490. if ( psz == NULL )
  3491. {
  3492. sc = ERROR_NOT_ENOUGH_MEMORY;
  3493. goto Cleanup;
  3494. } // if:
  3495. sc = ClusterEnum( hEnum, idxResource, &dwType, psz, &cch );
  3496. } // if: sc == ERROR_MORE_DATA
  3497. if ( sc == ERROR_SUCCESS )
  3498. {
  3499. hRes = OpenClusterResource( hClusterIn, psz );
  3500. if ( hRes == NULL )
  3501. {
  3502. sc = GetLastError();
  3503. goto Cleanup;
  3504. } // if:
  3505. fCloseResource = TRUE;
  3506. sc = ScIsCoreResource( hRes, &fIsCoreResource );
  3507. if ( sc != ERROR_SUCCESS )
  3508. {
  3509. goto Cleanup;
  3510. } // if:
  3511. //
  3512. // If the resource is not a core resource then close it and go around again.
  3513. //
  3514. if ( !fIsCoreResource )
  3515. {
  3516. CloseClusterResource( hRes );
  3517. hRes = NULL;
  3518. idxResource++;
  3519. continue;
  3520. } // if:
  3521. sc = ScIsQuorumCapableResource( hRes, &fIsQuorumCapableResource );
  3522. if ( sc != ERROR_SUCCESS )
  3523. {
  3524. goto Cleanup;
  3525. } // if:
  3526. //
  3527. // If this core resource is a quorum capable resource then it must be the quorom. If the caller
  3528. // has asked for the quorom resource then pass it back and leave the resource open, other wise
  3529. // close the resource and go around again.
  3530. //
  3531. if ( fIsQuorumCapableResource )
  3532. {
  3533. if ( phClusterQuorumResourceOut != NULL)
  3534. {
  3535. *phClusterQuorumResourceOut = hRes;
  3536. } // if:
  3537. else
  3538. {
  3539. CloseClusterResource( hRes );
  3540. } // else:
  3541. hRes = NULL;
  3542. idxResource++;
  3543. continue;
  3544. } // if:
  3545. //
  3546. // Since this core resource is not a quorum capable resource it is either the cluster
  3547. // name or the cluster IP address resource.
  3548. //
  3549. for ( idx = 0; *( g_pszCoreResourceTypes[ idx ] ) != '\0'; idx++ )
  3550. {
  3551. sc = ScIsResourceOfType( hRes, g_pszCoreResourceTypes[ idx ], &fIsResourceOfType );
  3552. if ( sc != ERROR_SUCCESS )
  3553. {
  3554. goto Cleanup;
  3555. } // if:
  3556. if ( !fIsResourceOfType )
  3557. {
  3558. continue;
  3559. } // if:
  3560. switch ( idx )
  3561. {
  3562. case CLUSTER_NAME :
  3563. if ( phClusterNameResourceOut != NULL )
  3564. {
  3565. *phClusterNameResourceOut = hRes;
  3566. fCloseResource = FALSE;
  3567. } // if:
  3568. break;
  3569. case CLUSTER_IP_ADDRESS :
  3570. if ( phClusterIPAddressResourceOut != NULL )
  3571. {
  3572. *phClusterIPAddressResourceOut = hRes;
  3573. fCloseResource = FALSE;
  3574. } // if:
  3575. break;
  3576. default:
  3577. goto Cleanup;
  3578. } // switch:
  3579. //
  3580. // If we get here then we broke from the switch above and we want out of
  3581. // this loop.
  3582. //
  3583. break;
  3584. } // for:
  3585. if ( fCloseResource )
  3586. {
  3587. CloseClusterResource( hRes );
  3588. } // if:
  3589. hRes = NULL;
  3590. idxResource++;
  3591. continue;
  3592. } // if: sc == ERROR_SUCCESS
  3593. else if ( sc == ERROR_NO_MORE_ITEMS )
  3594. {
  3595. sc = ERROR_SUCCESS;
  3596. break;
  3597. } // else if: sc == ERROR_NO_MORE_ITEMS
  3598. else
  3599. {
  3600. goto Cleanup;
  3601. } // else: sc has some other error...
  3602. break;
  3603. } // for:
  3604. Cleanup:
  3605. LocalFree( psz );
  3606. if ( hRes != NULL )
  3607. {
  3608. CloseClusterResource( hRes );
  3609. } // if:
  3610. if ( hEnum != NULL )
  3611. {
  3612. ClusterCloseEnum( hEnum );
  3613. } // if:
  3614. return sc;
  3615. } //*** ResUtilGetCoreClusterResources
  3616. //////////////////////////////////////////////////////////////////////////////
  3617. //++
  3618. //
  3619. // ResUtilGetResourceName()
  3620. //
  3621. // Description:
  3622. // Get the name of the resource that is passed in.
  3623. //
  3624. // Arguments:
  3625. // hResourceIn
  3626. // The resource whose name is sought.
  3627. //
  3628. // pszResourceNameOut
  3629. // Buffer to hold the resource's name.
  3630. //
  3631. // pcchResourceNameInOut
  3632. // The size of the buffer on input and the size required on output.
  3633. //
  3634. //
  3635. // Return Value:
  3636. // ERROR_SUCCESS
  3637. // ERROR_MORE_DATA
  3638. //
  3639. // Remarks:
  3640. // None.
  3641. //
  3642. //--
  3643. //////////////////////////////////////////////////////////////////////////////
  3644. DWORD
  3645. WINAPI
  3646. ResUtilGetResourceName(
  3647. HRESOURCE hResourceIn
  3648. , WCHAR * pszResourceNameOut
  3649. , DWORD * pcchResourceNameInOut
  3650. )
  3651. {
  3652. DWORD sc = ERROR_INVALID_PARAMETER;
  3653. WCHAR * psz = NULL;
  3654. DWORD cb;
  3655. HRESULT hr;
  3656. if ( hResourceIn == NULL )
  3657. {
  3658. goto Cleanup;
  3659. } // if:
  3660. if ( ( pszResourceNameOut == NULL ) || ( pcchResourceNameInOut == NULL ) )
  3661. {
  3662. goto Cleanup;
  3663. } // if:
  3664. psz = (WCHAR *) LocalAlloc( LPTR, (*pcchResourceNameInOut) * sizeof( WCHAR ) );
  3665. if ( psz == NULL )
  3666. {
  3667. sc = ERROR_NOT_ENOUGH_MEMORY;
  3668. goto Cleanup;
  3669. } // if:
  3670. sc = ClusterResourceControl(
  3671. hResourceIn
  3672. , NULL
  3673. , CLUSCTL_RESOURCE_GET_NAME
  3674. , NULL
  3675. , 0
  3676. , psz
  3677. , (*pcchResourceNameInOut) * sizeof( WCHAR )
  3678. , &cb
  3679. );
  3680. if ( sc == ERROR_MORE_DATA )
  3681. {
  3682. *pcchResourceNameInOut = ( cb / sizeof( WCHAR ) ) + 1;
  3683. goto Cleanup;
  3684. } // if:
  3685. if ( sc != ERROR_SUCCESS )
  3686. {
  3687. goto Cleanup;
  3688. } // if:
  3689. hr = StringCchCopy( pszResourceNameOut, *pcchResourceNameInOut, psz );
  3690. if ( FAILED( hr ) )
  3691. {
  3692. sc = HRESULT_CODE( hr );
  3693. goto Cleanup;
  3694. }
  3695. Cleanup:
  3696. LocalFree( psz );
  3697. return sc;
  3698. } //*** ResUtilGetResourceName