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.

1048 lines
29 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. cluster.c
  5. Abstract:
  6. Server side support for Cluster APIs dealing with the whole
  7. cluster.
  8. Author:
  9. John Vert (jvert) 9-Feb-1996
  10. Revision History:
  11. --*/
  12. #include "apip.h"
  13. #include "clusverp.h"
  14. #include "clusudef.h"
  15. #include <ntlsa.h>
  16. #include <ntmsv1_0.h>
  17. HCLUSTER_RPC
  18. s_ApiOpenCluster(
  19. IN handle_t IDL_handle,
  20. OUT error_status_t *Status
  21. )
  22. /*++
  23. Routine Description:
  24. Opens a handle to the cluster. This context handle is
  25. currently used only to handle cluster notify additions
  26. and deletions correctly.
  27. Added call to ApipConnectCallback which checks that connecting
  28. users have rights to open cluster.
  29. Rod Sharper 03/27/97
  30. Arguments:
  31. IDL_handle - RPC binding handle, not used.
  32. Status - Returns any error that may occur.
  33. Return Value:
  34. A context handle to a cluster object if successful
  35. NULL otherwise.
  36. History:
  37. RodSh 27-Mar-1997 Modified to support secured user connections.
  38. --*/
  39. {
  40. PAPI_HANDLE Handle;
  41. Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
  42. if (Handle == NULL) {
  43. *Status = ERROR_NOT_ENOUGH_MEMORY;
  44. return(NULL);
  45. }
  46. *Status = ERROR_SUCCESS;
  47. Handle->Type = API_CLUSTER_HANDLE;
  48. Handle->Flags = 0;
  49. Handle->Cluster = NULL;
  50. InitializeListHead(&Handle->NotifyList);
  51. return(Handle);
  52. }
  53. error_status_t
  54. s_ApiCloseCluster(
  55. IN OUT HCLUSTER_RPC *phCluster
  56. )
  57. /*++
  58. Routine Description:
  59. Closes an open cluster context handle.
  60. Arguments:
  61. phCluster - Supplies a pointer to the HCLUSTER_RPC to be closed.
  62. Returns NULL
  63. Return Value:
  64. None.
  65. --*/
  66. {
  67. PAPI_HANDLE Handle;
  68. Handle = (PAPI_HANDLE)*phCluster;
  69. if ((Handle == NULL) || (Handle->Type != API_CLUSTER_HANDLE)) {
  70. return(ERROR_INVALID_HANDLE);
  71. }
  72. ApipRundownNotify(Handle);
  73. LocalFree(*phCluster);
  74. *phCluster = NULL;
  75. return(ERROR_SUCCESS);
  76. }
  77. VOID
  78. HCLUSTER_RPC_rundown(
  79. IN HCLUSTER_RPC Cluster
  80. )
  81. /*++
  82. Routine Description:
  83. RPC rundown procedure for a HCLUSTER_RPC. Just closes the handle.
  84. Arguments:
  85. Cluster - Supplies the HCLUSTER_RPC that is to be rundown.
  86. Return Value:
  87. None.
  88. --*/
  89. {
  90. s_ApiCloseCluster(&Cluster);
  91. }
  92. error_status_t
  93. s_ApiSetClusterName(
  94. IN handle_t IDL_handle,
  95. IN LPCWSTR NewClusterName
  96. )
  97. /*++
  98. Routine Description:
  99. Changes the current cluster's name.
  100. Arguments:
  101. IDL_handle - RPC binding handle, not used
  102. NewClusterName - Supplies the new name of the cluster.
  103. Return Value:
  104. ERROR_SUCCESS if successful
  105. Win32 error code otherwise
  106. --*/
  107. {
  108. DWORD Status = ERROR_SUCCESS;
  109. DWORD dwSize;
  110. LPWSTR pszClusterName = NULL;
  111. API_CHECK_INIT();
  112. //
  113. // Get the cluster name, which is kept in the root of the
  114. // cluster registry under the "ClusterName" value, call the
  115. // FM only if the new name is different
  116. //
  117. dwSize = (MAX_COMPUTERNAME_LENGTH+1)*sizeof(WCHAR);
  118. retry:
  119. pszClusterName = (LPWSTR)LocalAlloc(LMEM_FIXED, dwSize);
  120. if (pszClusterName == NULL) {
  121. Status = ERROR_NOT_ENOUGH_MEMORY;
  122. goto FnExit;
  123. }
  124. Status = DmQueryValue(DmClusterParametersKey,
  125. CLUSREG_NAME_CLUS_NAME,
  126. NULL,
  127. (LPBYTE)pszClusterName,
  128. &dwSize);
  129. if (Status == ERROR_MORE_DATA) {
  130. //
  131. // Try again with a bigger buffer.
  132. //
  133. LocalFree(pszClusterName);
  134. goto retry;
  135. }
  136. if ( Status == ERROR_SUCCESS ) {
  137. LPWSTR pszNewNameUpperCase = NULL;
  138. pszNewNameUpperCase = (LPWSTR) LocalAlloc(
  139. LMEM_FIXED,
  140. (lstrlenW(NewClusterName) + 1) *
  141. sizeof(*NewClusterName)
  142. );
  143. if (pszNewNameUpperCase != NULL) {
  144. lstrcpyW( pszNewNameUpperCase, NewClusterName );
  145. _wcsupr( pszNewNameUpperCase );
  146. Status = FmChangeClusterName(pszNewNameUpperCase, pszClusterName);
  147. LocalFree( pszNewNameUpperCase );
  148. }
  149. else {
  150. Status = ERROR_NOT_ENOUGH_MEMORY;
  151. }
  152. }
  153. FnExit:
  154. if ( pszClusterName ) LocalFree( pszClusterName );
  155. return(Status);
  156. }
  157. error_status_t
  158. s_ApiGetClusterName(
  159. IN handle_t IDL_handle,
  160. OUT LPWSTR *ClusterName,
  161. OUT LPWSTR *NodeName
  162. )
  163. /*++
  164. Routine Description:
  165. Returns the current cluster name and the name of the
  166. node this RPC connection is to.
  167. Arguments:
  168. IDL_handle - RPC binding handle, not used
  169. ClusterName - Returns a pointer to the cluster name.
  170. This memory must be freed by the client side.
  171. NodeName - Returns a pointer to the node name.
  172. This memory must be freed by the client side.
  173. Return Value:
  174. ERROR_SUCCESS if successful
  175. Win32 error code otherwise
  176. --*/
  177. {
  178. DWORD Size;
  179. DWORD Status=ERROR_SUCCESS;
  180. //
  181. // Get the current node name
  182. //
  183. *ClusterName = NULL;
  184. Size = MAX_COMPUTERNAME_LENGTH+1;
  185. *NodeName = MIDL_user_allocate(Size*sizeof(WCHAR));
  186. if (*NodeName == NULL) {
  187. Status = ERROR_NOT_ENOUGH_MEMORY;
  188. goto FnExit;
  189. }
  190. GetComputerNameW(*NodeName, &Size);
  191. //
  192. // Get the cluster name, which is kept in the root of the
  193. // cluster registry under the "ClusterName" value.
  194. //
  195. Status = ERROR_SUCCESS;
  196. Size = (MAX_COMPUTERNAME_LENGTH+1)*sizeof(WCHAR);
  197. retry:
  198. *ClusterName = MIDL_user_allocate(Size);
  199. if (*ClusterName == NULL) {
  200. Status = ERROR_NOT_ENOUGH_MEMORY;
  201. goto FnExit;
  202. }
  203. Status = DmQueryValue(DmClusterParametersKey,
  204. CLUSREG_NAME_CLUS_NAME,
  205. NULL,
  206. (LPBYTE)*ClusterName,
  207. &Size);
  208. if (Status == ERROR_MORE_DATA) {
  209. //
  210. // Try again with a bigger buffer.
  211. //
  212. MIDL_user_free(*ClusterName);
  213. goto retry;
  214. }
  215. FnExit:
  216. if (Status == ERROR_SUCCESS) {
  217. return(ERROR_SUCCESS);
  218. }
  219. if (*NodeName) MIDL_user_free(*NodeName);
  220. if (*ClusterName) MIDL_user_free(*ClusterName);
  221. *NodeName = NULL;
  222. *ClusterName = NULL;
  223. return(Status);
  224. }
  225. error_status_t
  226. s_ApiGetClusterVersion(
  227. IN handle_t IDL_handle,
  228. OUT LPWORD lpwMajorVersion,
  229. OUT LPWORD lpwMinorVersion,
  230. OUT LPWORD lpwBuildNumber,
  231. OUT LPWSTR *lpszVendorId,
  232. OUT LPWSTR *lpszCSDVersion
  233. )
  234. /*++
  235. Routine Description:
  236. Returns the current cluster version information.
  237. Arguments:
  238. IDL_handle - RPC binding handle, not used
  239. lpdwMajorVersion - Returns the major version number of the cluster software
  240. lpdwMinorVersion - Returns the minor version number of the cluster software
  241. lpszVendorId - Returns a pointer to the vendor name. This memory must be
  242. freed by the client side.
  243. lpszCSDVersion - Returns a pointer to the current CSD description. This memory
  244. must be freed by the client side.
  245. N.B. The CSD Version of a cluster is currently the same as the CSD
  246. Version of the base operating system.
  247. Return Value:
  248. ERROR_SUCCESS if successful
  249. Win32 error code otherwise.
  250. --*/
  251. {
  252. LPWSTR VendorString = NULL;
  253. LPWSTR CsdString = NULL;
  254. DWORD Length;
  255. OSVERSIONINFO OsVersionInfo;
  256. DWORD dwStatus = ERROR_SUCCESS;
  257. Length = lstrlenA(VER_CLUSTER_PRODUCTNAME_STR)+1;
  258. VendorString = MIDL_user_allocate(Length*sizeof(WCHAR));
  259. if (VendorString == NULL)
  260. {
  261. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  262. goto FnExit;
  263. }
  264. mbstowcs(VendorString, VER_CLUSTER_PRODUCTNAME_STR, Length);
  265. OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  266. GetVersionExW(&OsVersionInfo);
  267. Length = lstrlenW(OsVersionInfo.szCSDVersion)+1;
  268. CsdString = MIDL_user_allocate(Length*sizeof(WCHAR));
  269. if (CsdString == NULL) {
  270. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  271. goto FnExit;
  272. }
  273. lstrcpyW(CsdString, OsVersionInfo.szCSDVersion);
  274. *lpszCSDVersion = CsdString;
  275. *lpszVendorId = VendorString;
  276. *lpwMajorVersion = VER_PRODUCTVERSION_W >> 8;
  277. *lpwMinorVersion = VER_PRODUCTVERSION_W & 0xff;
  278. *lpwBuildNumber = (WORD)(CLUSTER_GET_MINOR_VERSION(CsMyHighestVersion));
  279. FnExit:
  280. if (dwStatus != ERROR_SUCCESS)
  281. {
  282. if (VendorString)
  283. MIDL_user_free(VendorString);
  284. if (CsdString)
  285. MIDL_user_free(CsdString);
  286. }
  287. return(dwStatus);
  288. }
  289. error_status_t
  290. s_ApiGetClusterVersion2(
  291. IN handle_t IDL_handle,
  292. OUT LPWORD lpwMajorVersion,
  293. OUT LPWORD lpwMinorVersion,
  294. OUT LPWORD lpwBuildNumber,
  295. OUT LPWSTR *lpszVendorId,
  296. OUT LPWSTR *lpszCSDVersion,
  297. OUT PCLUSTER_OPERATIONAL_VERSION_INFO *ppClusterOpVerInfo
  298. )
  299. /*++
  300. Routine Description:
  301. Returns the current cluster version information.
  302. Arguments:
  303. IDL_handle - RPC binding handle, not used
  304. lpdwMajorVersion - Returns the major version number of the cluster software
  305. lpdwMinorVersion - Returns the minor version number of the cluster software
  306. lpszVendorId - Returns a pointer to the vendor name. This memory must be
  307. freed by the client side.
  308. lpszCSDVersion - Returns a pointer to the current CSD description. This memory
  309. must be freed by the client side.
  310. N.B. The CSD Version of a cluster is currently the same as the CSD
  311. Version of the base operating system.
  312. Return Value:
  313. ERROR_SUCCESS if successful
  314. Win32 error code otherwise.
  315. --*/
  316. {
  317. LPWSTR VendorString = NULL;
  318. LPWSTR CsdString = NULL;
  319. DWORD Length;
  320. OSVERSIONINFO OsVersionInfo;
  321. DWORD dwStatus;
  322. PCLUSTER_OPERATIONAL_VERSION_INFO pClusterOpVerInfo=NULL;
  323. *lpszVendorId = NULL;
  324. *lpszCSDVersion = NULL;
  325. *ppClusterOpVerInfo = NULL;
  326. Length = lstrlenA(VER_CLUSTER_PRODUCTNAME_STR)+1;
  327. VendorString = MIDL_user_allocate(Length*sizeof(WCHAR));
  328. if (VendorString == NULL) {
  329. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  330. goto FnExit;
  331. }
  332. mbstowcs(VendorString, VER_CLUSTER_PRODUCTNAME_STR, Length);
  333. OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  334. GetVersionExW(&OsVersionInfo);
  335. Length = lstrlenW(OsVersionInfo.szCSDVersion)+1;
  336. CsdString = MIDL_user_allocate(Length*sizeof(WCHAR));
  337. if (CsdString == NULL) {
  338. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  339. goto FnExit;
  340. }
  341. lstrcpyW(CsdString, OsVersionInfo.szCSDVersion);
  342. pClusterOpVerInfo = MIDL_user_allocate(sizeof(CLUSTER_OPERATIONAL_VERSION_INFO));
  343. if (pClusterOpVerInfo == NULL) {
  344. dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  345. goto FnExit;
  346. }
  347. pClusterOpVerInfo->dwSize = sizeof(CLUSTER_OPERATIONAL_VERSION_INFO);
  348. pClusterOpVerInfo->dwReserved = 0;
  349. dwStatus = NmGetClusterOperationalVersion(&(pClusterOpVerInfo->dwClusterHighestVersion),
  350. &(pClusterOpVerInfo->dwClusterLowestVersion),
  351. &(pClusterOpVerInfo->dwFlags));
  352. *lpszCSDVersion = CsdString;
  353. *lpszVendorId = VendorString;
  354. *ppClusterOpVerInfo = pClusterOpVerInfo;
  355. *lpwMajorVersion = VER_PRODUCTVERSION_W >> 8;
  356. *lpwMinorVersion = VER_PRODUCTVERSION_W & 0xff;
  357. *lpwBuildNumber = (WORD)CLUSTER_GET_MINOR_VERSION(CsMyHighestVersion);
  358. FnExit:
  359. if (dwStatus != ERROR_SUCCESS)
  360. {
  361. // free the strings
  362. if (VendorString) MIDL_user_free(VendorString);
  363. if (CsdString) MIDL_user_free(CsdString);
  364. if (pClusterOpVerInfo) MIDL_user_free(pClusterOpVerInfo);
  365. }
  366. return(ERROR_SUCCESS);
  367. }
  368. error_status_t
  369. s_ApiGetQuorumResource(
  370. IN handle_t IDL_handle,
  371. OUT LPWSTR *ppszResourceName,
  372. OUT LPWSTR *ppszClusFileRootPath,
  373. OUT DWORD *pdwMaxQuorumLogSize
  374. )
  375. /*++
  376. Routine Description:
  377. Gets the current cluster quorum resource.
  378. Arguments:
  379. IDL_handle - RPC binding handle, not used.
  380. *ppszResourceName - Returns a pointer to the current quorum resource name. This
  381. memory must be freed by the client side.
  382. *ppszClusFileRootPath - Returns the root path where the permanent cluster files are
  383. stored.
  384. *pdwMaxQuorumLogSize - Returns the size at which the quorum log path is set.
  385. Return Value:
  386. ERROR_SUCCESS if successful
  387. Win32 error code otherwise.
  388. --*/
  389. {
  390. DWORD Status;
  391. LPWSTR quorumId = NULL;
  392. DWORD idMaxSize = 0;
  393. DWORD idSize = 0;
  394. PFM_RESOURCE pResource=NULL;
  395. LPWSTR pszResourceName=NULL;
  396. LPWSTR pszClusFileRootPath=NULL;
  397. LPWSTR pszLogPath=NULL;
  398. API_CHECK_INIT();
  399. //
  400. // Get the quorum resource value.
  401. //
  402. Status = DmQuerySz( DmQuorumKey,
  403. CLUSREG_NAME_QUORUM_RESOURCE,
  404. (LPWSTR*)&quorumId,
  405. &idMaxSize,
  406. &idSize);
  407. if (Status != ERROR_SUCCESS) {
  408. ClRtlLogPrint(LOG_ERROR,
  409. "[API] s_ApiGetQuorumResource Failed to get quorum resource, error %1!u!.\n",
  410. Status);
  411. goto FnExit;
  412. }
  413. //
  414. // Reference the specified resource ID.
  415. //
  416. pResource = OmReferenceObjectById( ObjectTypeResource, quorumId );
  417. if (pResource == NULL) {
  418. Status = ERROR_RESOURCE_NOT_FOUND;
  419. ClRtlLogPrint(LOG_ERROR,
  420. "[API] s_ApiGetQuorumResource Failed to find quorum resource object, error %1!u!\n",
  421. Status);
  422. goto FnExit;
  423. }
  424. //
  425. // Allocate buffer for returning the resource name.
  426. //
  427. pszResourceName = MIDL_user_allocate((lstrlenW(OmObjectName(pResource))+1)*sizeof(WCHAR));
  428. if (pszResourceName == NULL) {
  429. Status = ERROR_NOT_ENOUGH_MEMORY;
  430. goto FnExit;
  431. }
  432. lstrcpyW(pszResourceName, OmObjectName(pResource));
  433. //
  434. // Get the root path for cluster temporary files
  435. //
  436. idMaxSize = 0;
  437. idSize = 0;
  438. Status = DmQuerySz( DmQuorumKey,
  439. cszPath,
  440. (LPWSTR*)&pszLogPath,
  441. &idMaxSize,
  442. &idSize);
  443. if (Status != ERROR_SUCCESS) {
  444. ClRtlLogPrint(LOG_ERROR,
  445. "[API] s_ApiGetQuorumResource Failed to get the log path, error %1!u!.\n",
  446. Status);
  447. goto FnExit;
  448. }
  449. //
  450. // Allocate buffer for returning the resource name.
  451. //
  452. pszClusFileRootPath = MIDL_user_allocate((lstrlenW(pszLogPath)+1)*sizeof(WCHAR));
  453. if (pszClusFileRootPath == NULL) {
  454. Status = ERROR_NOT_ENOUGH_MEMORY;
  455. goto FnExit;
  456. }
  457. lstrcpyW(pszClusFileRootPath, pszLogPath);
  458. *ppszResourceName = pszResourceName;
  459. *ppszClusFileRootPath = pszClusFileRootPath;
  460. DmGetQuorumLogMaxSize(pdwMaxQuorumLogSize);
  461. FnExit:
  462. if (pResource) OmDereferenceObject(pResource);
  463. if (pszLogPath) LocalFree(pszLogPath);
  464. if (quorumId) LocalFree(quorumId);
  465. if (Status != ERROR_SUCCESS)
  466. {
  467. if (pszResourceName) MIDL_user_free(pszResourceName);
  468. if (pszClusFileRootPath) MIDL_user_free(pszClusFileRootPath);
  469. }
  470. return(Status);
  471. }
  472. error_status_t
  473. s_ApiSetQuorumResource(
  474. IN HRES_RPC hResource,
  475. IN LPCWSTR lpszClusFileRootPath,
  476. IN DWORD dwMaxQuorumLogSize
  477. )
  478. /*++
  479. Routine Description:
  480. Sets the current cluster quorum resource.
  481. Arguments:
  482. hResource - Supplies a handle to the resource that should be the cluster
  483. quorum resource.
  484. lpszClusFileRootPath - The root path for storing
  485. permananent cluster maintenace files.
  486. dwMaxQuorumLogSize - The maximum size of the quorum logs before they are
  487. reset by checkpointing. If 0, the default is used.
  488. Return Value:
  489. ERROR_SUCCESS if successful
  490. Win32 error code otherwise.
  491. --*/
  492. {
  493. DWORD Status;
  494. PFM_RESOURCE Resource;
  495. LPCWSTR lpszPathName = NULL;
  496. API_CHECK_INIT();
  497. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  498. //
  499. // Chittur Subbaraman (chitturs) - 1/6/99
  500. //
  501. // Check whether the user is passing in a pointer to a NULL character
  502. // as the second parameter. If not, pass the parameter passed by the
  503. // user
  504. //
  505. if ( ( ARGUMENT_PRESENT( lpszClusFileRootPath ) ) &&
  506. ( *lpszClusFileRootPath != L'\0' ) )
  507. {
  508. lpszPathName = lpszClusFileRootPath;
  509. }
  510. //
  511. // Let FM decide if this operation can be completed.
  512. //
  513. Status = FmSetQuorumResource(Resource, lpszPathName, dwMaxQuorumLogSize );
  514. if ( Status != ERROR_SUCCESS ) {
  515. return(Status);
  516. }
  517. //Update the path
  518. return(Status);
  519. }
  520. error_status_t
  521. s_ApiSetNetworkPriorityOrder(
  522. IN handle_t IDL_handle,
  523. IN DWORD NetworkCount,
  524. IN LPWSTR *NetworkIdList
  525. )
  526. /*++
  527. Routine Description:
  528. Sets the priority order for internal (intracluster) networks.
  529. Arguments:
  530. IDL_handle - RPC binding handle, not used
  531. NetworkCount - The count of networks in the NetworkList
  532. NetworkList - An array of pointers to network IDs.
  533. Return Value:
  534. ERROR_SUCCESS if successful
  535. Win32 error code otherwise.
  536. --*/
  537. {
  538. API_CHECK_INIT();
  539. return(
  540. NmSetNetworkPriorityOrder(
  541. NetworkCount,
  542. NetworkIdList
  543. )
  544. );
  545. }
  546. error_status_t
  547. s_ApiBackupClusterDatabase(
  548. IN handle_t IDL_handle,
  549. IN LPCWSTR lpszPathName
  550. )
  551. /*++
  552. Routine Description:
  553. Requests for backup of the quorum log file and the checkpoint file.
  554. Argument:
  555. IDL_handle - RPC binding handle, not used
  556. lpszPathName - The directory path name where the files have to be
  557. backed up. This path must be visible to the node
  558. on which the quorum resource is online.
  559. Return Value:
  560. ERROR_SUCCESS if successful
  561. Win32 error code otherwise.
  562. --*/
  563. {
  564. API_CHECK_INIT();
  565. //
  566. // Let FM decide if this operation can be completed.
  567. //
  568. return( FmBackupClusterDatabase( lpszPathName ) );
  569. }
  570. // #define SetServiceAccountPasswordDebug 1
  571. error_status_t
  572. s_ApiSetServiceAccountPassword(
  573. IN handle_t IDL_handle,
  574. IN LPWSTR lpszNewPassword,
  575. IN DWORD dwFlags,
  576. OUT IDL_CLUSTER_SET_PASSWORD_STATUS *ReturnStatusBufferPtr,
  577. IN DWORD ReturnStatusBufferSize,
  578. OUT DWORD *SizeReturned,
  579. OUT DWORD *ExpectedBufferSize
  580. )
  581. /*++
  582. Routine Description:
  583. Change cluster service account password on Service Control Manager
  584. Database and LSA password cache on every node of cluster.
  585. Return execution status on each node.
  586. Argument:
  587. IDL_handle - Input parameter, RPC binding handle.
  588. lpszNewPassword - Input parameter, new password for cluster service account.
  589. dwFlags - Describing how the password update should be made to
  590. the cluster. The dwFlags parameter is optional. If set, the
  591. following value is valid:
  592. CLUSTER_SET_PASSWORD_IGNORE_DOWN_NODES
  593. Apply the update even if some nodes are not
  594. actively participating in the cluster (i.e. not
  595. ClusterNodeStateUp or ClusterNodeStatePaused).
  596. By default, the update is only applied if all
  597. nodes are up.
  598. ReturnStatusBufferPtr - Output parameter, pointer to return status buffer.
  599. ReturnStatusBufferSize - Input paramter, the length of return status
  600. buffer, in number of elements.
  601. SizeReturned - Output parameter, the number of elements written to return
  602. status buffer.
  603. ExpectedBufferSize - Output parameter, expected return status buffer size
  604. (in number of entries) when ReturnStatusBuffer is
  605. too small.
  606. Return Value:
  607. ERROR_SUCCESS if successful
  608. Win32 error code otherwise.
  609. --*/
  610. {
  611. DWORD Status=ERROR_SUCCESS;
  612. RPC_AUTHZ_HANDLE AuthzHandle = NULL;
  613. unsigned long AuthnLevel = 0;
  614. HANDLE TokenHandle = NULL;
  615. TOKEN_STATISTICS TokenSta;
  616. DWORD ReturnSize = 0;
  617. PSECURITY_LOGON_SESSION_DATA SecLogSesData = NULL;
  618. NTSTATUS NtStatus = STATUS_SUCCESS;
  619. #ifdef SetServiceAccountPasswordDebug
  620. // test
  621. WCHAR ComputerName[100];
  622. DWORD ComputerNameSize=100;
  623. static int once=0;
  624. // test
  625. #endif
  626. API_CHECK_INIT();
  627. ClRtlLogPrint(LOG_NOISE,
  628. "s_ApiSetServiceAccountPassword(): Changing account password.\n"
  629. );
  630. #ifdef SetServiceAccountPasswordDebug
  631. ClRtlLogPrint(LOG_NOISE,
  632. "s_ApiSetServiceAccountPassword(): NewPassword = %1!ws!.\n",
  633. lpszNewPassword
  634. );
  635. ClRtlLogPrint(LOG_NOISE,
  636. "s_ApiSetServiceAccountPassword(): ReturnStatusBufferSize = %1!u!.\n",
  637. ReturnStatusBufferSize
  638. );
  639. // test
  640. #endif
  641. // check privilege attributes of the authenticated client that made the remote procedure call.
  642. Status = RpcBindingInqAuthClient(IDL_handle, // The client binding handle of the client that made
  643. // the remote procedure call.
  644. &AuthzHandle, // Returns a pointer to a handle to the privileged information
  645. // for the client application that made the remote procedure
  646. // call
  647. NULL,
  648. &AuthnLevel, // Returns a pointer to the level of authentication requested
  649. // by the client application that made the remote procedure call
  650. NULL,
  651. NULL
  652. );
  653. if (Status == RPC_S_OK)
  654. {
  655. #ifdef SetServiceAccountPasswordDebug
  656. ClRtlLogPrint(LOG_NOISE,
  657. "s_ApiSetServiceAccountPassword()/RpcBindingInqAuthClient() succeeded. AuthnLevel = %1!u!.\n",
  658. AuthnLevel
  659. );
  660. #endif
  661. if (AuthnLevel < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
  662. {
  663. ClRtlLogPrint(LOG_CRITICAL,
  664. "s_ApiSetServiceAccountPassword()/RpcBindingInqAuthClient(): AuthnLevel (%1!u!) < RPC_C_AUTHN_LEVEL_PKT_PRIVACY.\n",
  665. AuthnLevel
  666. );
  667. Status = ERROR_ACCESS_DENIED;
  668. goto ErrorExit;
  669. }
  670. else
  671. {
  672. #ifdef SetServiceAccountPasswordDebug
  673. ClRtlLogPrint(LOG_NOISE,
  674. "s_ApiSetServiceAccountPassword()/RpcBindingInqAuthClient(): AuthnLevel (%1!u!) fine.\n",
  675. AuthnLevel
  676. );
  677. #endif
  678. }
  679. }
  680. else
  681. {
  682. ClRtlLogPrint(LOG_CRITICAL,
  683. "s_ApiSetServiceAccountPassword()/RpcBindingInqAuthClient() failed. Error code = %1!u!.\n",
  684. Status
  685. );
  686. goto ErrorExit;
  687. }
  688. // Get domain name and account name
  689. if (!OpenProcessToken(GetCurrentProcess(), // Handle to the process whose access token is opened.
  690. TOKEN_QUERY, // Access mask
  691. &TokenHandle // Pointer to a handle identifying the newly-opened access token
  692. // when the function returns.
  693. ))
  694. {
  695. Status=GetLastError();
  696. ClRtlLogPrint(LOG_CRITICAL,
  697. "s_ApiSetServiceAccountPassword()/OpenProcessToken() failed. Error code = %1!u!.\n",
  698. Status);
  699. goto ErrorExit;
  700. }
  701. Status = GetTokenInformation(TokenHandle, // Handle to an access token from which information is retrieved.
  702. TokenStatistics,
  703. &TokenSta, // The buffer receives a TOKEN_STATISTICS structure containing
  704. // various token statistics.
  705. sizeof(TokenSta),
  706. &ReturnSize
  707. );
  708. if ( (Status==0) || (ReturnSize > sizeof(TokenSta)) )
  709. {
  710. Status=GetLastError();
  711. ClRtlLogPrint(LOG_CRITICAL,
  712. "s_ApiSetServiceAccountPassword()/GetTokenInformation() failed. Error code = %1!u!.\n",
  713. Status);
  714. goto ErrorExit;
  715. }
  716. NtStatus = LsaGetLogonSessionData(&(TokenSta.AuthenticationId), // Specifies a pointer to a LUID that
  717. // identifies the logon session whose
  718. // information will be retrieved.
  719. &SecLogSesData // Address of a pointer to a SECURITY_LOGON_SESSION_DATA
  720. // structure containing information on the logon session
  721. );
  722. if (NtStatus != STATUS_SUCCESS)
  723. {
  724. ClRtlLogPrint(LOG_CRITICAL,
  725. "s_ApiSetServiceAccountPassword()/LsaGetLogonSessionData() failed. Error code = %1!u!.\n",
  726. LsaNtStatusToWinError(NtStatus));
  727. Status=LsaNtStatusToWinError(NtStatus);
  728. goto ErrorExit;
  729. }
  730. #ifdef SetServiceAccountPasswordDebug
  731. // test
  732. ClRtlLogPrint(LOG_NOISE,
  733. "s_ApiSetServiceAccountPassword()/DomainName = %1!ws!\n",
  734. SecLogSesData->LogonDomain.Buffer);
  735. ClRtlLogPrint(LOG_NOISE,
  736. "s_ApiSetServiceAccountPassword()/AccountName = %1!ws!\n",
  737. SecLogSesData->UserName.Buffer);
  738. ClRtlLogPrint(LOG_NOISE,
  739. "s_ApiSetServiceAccountPassword()/AuthenticationPackage = %1!ws!\n",
  740. SecLogSesData->AuthenticationPackage.Buffer);
  741. ClRtlLogPrint(LOG_NOISE,
  742. "s_ApiSetServiceAccountPassword()/LogonType = %1!u!\n",
  743. SecLogSesData->LogonType);
  744. // test
  745. #endif
  746. ////////////////////////////////////////////////////////////////////////////////////////
  747. // Call NmSetServiceAccountPassword()
  748. Status = NmSetServiceAccountPassword(
  749. SecLogSesData->LogonDomain.Buffer,
  750. SecLogSesData->UserName.Buffer,
  751. lpszNewPassword,
  752. dwFlags,
  753. (PCLUSTER_SET_PASSWORD_STATUS) ReturnStatusBufferPtr,
  754. ReturnStatusBufferSize,
  755. SizeReturned,
  756. ExpectedBufferSize
  757. );
  758. RtlSecureZeroMemory(lpszNewPassword, (wcslen(lpszNewPassword)+1)*sizeof(WCHAR));
  759. ErrorExit:
  760. if (TokenHandle!=NULL)
  761. {
  762. if (!CloseHandle(TokenHandle))
  763. ClRtlLogPrint(LOG_ERROR,
  764. "s_ApiSetServiceAccountPassword(): CloseHandle() FAILED. Error code=%1!u!\n",
  765. GetLastError()
  766. );
  767. }
  768. if (SecLogSesData!=NULL)
  769. {
  770. NtStatus = LsaFreeReturnBuffer(SecLogSesData);
  771. if (NtStatus!=STATUS_SUCCESS)
  772. ClRtlLogPrint(LOG_ERROR,
  773. "s_ApiSetServiceAccountPassword(): LsaFreeReturnBuffer() FAILED. Error code=%1!u!\n",
  774. LsaNtStatusToWinError(NtStatus)
  775. );
  776. }
  777. // Return status can not be ERROR_INVALID_HANDLE, since this will trigger the
  778. // re-try logic at the RPC client. So ERROR_INVALID_HANDLE is converted to some
  779. // value, which no Win32 function will ever set its return status to, before
  780. // it is sent back to RPC client.
  781. // Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29
  782. // is reserved for application-defined error codes; no system error code has
  783. // this bit set. If you are defining an error code for your application, set this
  784. // bit to one. That indicates that the error code has been defined by an application,
  785. // and ensures that your error code does not conflict with any error codes defined
  786. // by the system.
  787. if ( Status == ERROR_INVALID_HANDLE ) {
  788. Status |= 0x20000000; // Bit 29 set.
  789. }
  790. return (Status);
  791. } // s_ApiSetServiceAccountPassword()